@launchchair/agent 0.4.12 → 0.5.1
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 +27 -9
- package/README.md +62 -14
- package/launchchair-cli.mjs +176 -17
- package/local-bridge.mjs +2 -1
- package/mcp-bridge-server.mjs +80 -53
- package/mcp-capabilities.mjs +227 -0
- package/mcp-widget.html +1203 -0
- package/mcp-widgets.mjs +74 -0
- package/package.json +4 -1
- package/project-workspace.mjs +4 -1
- package/server.json +4 -4
package/AGENTS.md
CHANGED
|
@@ -35,6 +35,9 @@ mkdir -p "$HOME/launchchair-agent"
|
|
|
35
35
|
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/local-bridge.mjs" -o "$HOME/launchchair-agent/local-bridge.mjs"
|
|
36
36
|
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/launchchair-cli.mjs" -o "$HOME/launchchair-agent/launchchair-cli.mjs"
|
|
37
37
|
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/mcp-bridge-server.mjs" -o "$HOME/launchchair-agent/mcp-bridge-server.mjs"
|
|
38
|
+
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/mcp-capabilities.mjs" -o "$HOME/launchchair-agent/mcp-capabilities.mjs"
|
|
39
|
+
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/mcp-widgets.mjs" -o "$HOME/launchchair-agent/mcp-widgets.mjs"
|
|
40
|
+
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/mcp-widget.html" -o "$HOME/launchchair-agent/mcp-widget.html"
|
|
38
41
|
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/project-workspace.mjs" -o "$HOME/launchchair-agent/project-workspace.mjs"
|
|
39
42
|
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/runner-command.mjs" -o "$HOME/launchchair-agent/runner-command.mjs"
|
|
40
43
|
curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/codex-runner.mjs" -o "$HOME/launchchair-agent/codex-runner.mjs"
|
|
@@ -75,7 +78,7 @@ LAUNCHCHAIR_BASE_URL="https://www.launchchair.io"
|
|
|
75
78
|
LAUNCHCHAIR_PROJECT_ID="optional project UUID; omit or leave blank if creating or discovering a project"
|
|
76
79
|
```
|
|
77
80
|
|
|
78
|
-
`launchchair login`
|
|
81
|
+
`launchchair login` saves the token to `~/.launchchair/config.json`, shared by the CLI and MCP. Use `LAUNCHCHAIR_AGENT_TOKEN` as a manual fallback when browser login is skipped. A fresh saved login takes precedence over stale environment credentials; logout disables authentication until login. Use a separate `LAUNCHCHAIR_CONFIG_DIR` for a separate per-client account.
|
|
79
82
|
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. Guided setup verifies standards-compliant MCP initialize and tool discovery before it reports success.
|
|
80
83
|
|
|
81
84
|
For Codex Desktop local runs, choose the runner globally and bind each project clone independently:
|
|
@@ -122,14 +125,15 @@ Prefer `launchchair setup codex` so the CLI writes native config and verifies MC
|
|
|
122
125
|
|
|
123
126
|
## What To Do First In A Fresh Chat
|
|
124
127
|
|
|
125
|
-
1.
|
|
126
|
-
2.
|
|
128
|
+
1. Call `launchchair_status`. If login is required, call `launchchair_login`, present the approval URL, then poll `launchchair_login_status` at its returned interval.
|
|
129
|
+
2. If paid access is required, present the returned upgrade URL and wait for the user to upgrade before resuming the blocked operation.
|
|
127
130
|
3. If `LAUNCHCHAIR_PROJECT_ID` is blank and the user named a project, call `launchchair_list_projects` and select the matching project.
|
|
128
131
|
4. If the user asks to create a new LaunchChair project, call `launchchair_create_project`.
|
|
129
|
-
5.
|
|
130
|
-
6.
|
|
132
|
+
5. To pick up queued work or advance the workflow, call `launchchair_next_step`, execute its claimed prompt in the current host agent, and submit the result with `launchchair_complete_run`.
|
|
133
|
+
6. Use `launchchair_run_once` or `executionMode=local_runner` only when the user explicitly requests a separate local runner.
|
|
131
134
|
7. If LaunchChair asks for a user-choice bucket such as wedge, pricing, or feature direction, call `launchchair_select_choice`. Do not use generic SPEC_UPDATE apply for user-choice buckets.
|
|
132
135
|
8. When the user asks for validation scores or wants to compare ideas, call `launchchair_get_scorecards`. Report validation scorecards separately from generated direction-option scores.
|
|
136
|
+
9. In hosts that support MCP Apps, present `launchchair_show_choices` at a choice step and after a selection, `launchchair_show_phase_synthesis` after phase completion, and `launchchair_show_validation_scores` for validation results. Their Next action controls return work to the host agent. If UI is unsupported, summarize the structured result and show the returned URLs.
|
|
133
137
|
|
|
134
138
|
## Consent Behavior
|
|
135
139
|
|
|
@@ -218,7 +222,7 @@ Avoid long explanations of local file searching when LaunchChair MCP tools are a
|
|
|
218
222
|
Run a full project loop:
|
|
219
223
|
|
|
220
224
|
```text
|
|
221
|
-
Call
|
|
225
|
+
Call launchchair_next_step with projectId and optional stopPhaseKey, execute the claimed prompt with the host's tools, and call launchchair_complete_run. Repeat until the requested target or a genuine checkpoint.
|
|
222
226
|
```
|
|
223
227
|
|
|
224
228
|
Create a project from a new idea:
|
|
@@ -233,18 +237,20 @@ Find a project by name:
|
|
|
233
237
|
Call launchchair_list_projects with query set to the user-provided project name.
|
|
234
238
|
```
|
|
235
239
|
|
|
236
|
-
|
|
240
|
+
Claim one queued UI job for execution by the current agent:
|
|
237
241
|
|
|
238
242
|
```text
|
|
239
|
-
Call
|
|
243
|
+
Call launchchair_next_step with projectId.
|
|
240
244
|
```
|
|
241
245
|
|
|
242
|
-
Run one queued UI job
|
|
246
|
+
Run one queued UI job through an explicitly requested local runner:
|
|
243
247
|
|
|
244
248
|
```bash
|
|
245
249
|
launchchair run-once
|
|
246
250
|
```
|
|
247
251
|
|
|
252
|
+
Every MCP tool is also accessible through `launchchair call TOOL --json '{...}'` or `--input FILE`. Use `launchchair tools --json` for schemas. Tool results are JSON, tool errors exit nonzero, and token secrets remain in private files. Prefer host execution for agents with connected GitHub/Vercel/Supabase tools.
|
|
253
|
+
|
|
248
254
|
Select a generated wedge:
|
|
249
255
|
|
|
250
256
|
```text
|
|
@@ -259,3 +265,15 @@ Call launchchair_select_choice with domain="wedge" and optionTitle or optionId.
|
|
|
259
265
|
- Do not run production SQL without explicit user authorization and a known project ref.
|
|
260
266
|
- Do not mark QA complete without matching evidence. For Feature projects, produce that evidence by running the repository-native or browser checks whenever possible.
|
|
261
267
|
- Do not search the whole filesystem for LaunchChair source when the public docs and MCP tools are available.
|
|
268
|
+
|
|
269
|
+
## MCP login and host execution
|
|
270
|
+
|
|
271
|
+
The MCP can start without a token. Call `launchchair_login`, show the returned LaunchChair approval URL, and call `launchchair_login_status` after approval. Respect its poll interval. Tokens are stored privately in the local config and never returned to the conversation. Existing tokens need a fresh owner-approved login for `tokens.manage`. Use `launchchair_create_token` to save a scoped credential file, `launchchair_list_tokens` for redacted metadata, and `launchchair_revoke_token`/`launchchair_logout` for cleanup.
|
|
272
|
+
|
|
273
|
+
Prefer `launchchair_next_step`, execute the claimed prompt in the current agent with its already-connected plugins, call `launchchair_complete_run`, and repeat. Do not spawn another model or local CLI unless explicitly requested (`executionMode=local_runner`). A waiting run is already claimed; poll it instead of executing it twice. Inspect forms/checklists with `launchchair_get_bucket`, save allowed patches with `launchchair_update_bucket`, and supply factual `executionEvidence` for setup and verification. Use `launchchair_get_starter` after validation to read the starter files and the host's GitHub/Vercel/Supabase tools to create and deploy the user's app. Bind the verified clone with `launchchair_bind_repository`. Use `stopPhaseKey=launch_sales` for the complete Product workflow.
|
|
274
|
+
|
|
275
|
+
Preserve a supplied idea and specified requirements, even with low validation scores. `ideaIntent=preserve` is the default. Report risks and continue the requested work when no score gate was requested; never pivot merely to improve a score. Choose a generated direction consistent with the supplied idea. Only use `ideaIntent=explore` for explicit discovery or pivot requests.
|
|
276
|
+
|
|
277
|
+
For “do not build until VERY high validation,” create candidates with `validationGate=very_high` (pain >=85, opportunity >=85, saturation <=30), validate through `market_validation`, and compare with `launchchair_compare_projects`. The gate is enforced on LaunchChair build/setup actions and cannot be weakened through generic mutations. Do not provision external resources until it passes. If no candidate qualifies, report the unmet thresholds honestly. Scores are research estimates, not a guarantee of market demand. Do not fabricate evidence or replace validation scores with direction-option scores.
|
|
278
|
+
|
|
279
|
+
Research sources, competitor notes, Pexels assets, logo upload, form/checklist data, prompts, build cards, run management, and markdown exports are available as MCP tools. Tool descriptions distinguish data writes from actual external execution. Existing user authorization carries forward; ask only at a genuine missing authorization or information boundary.
|
package/README.md
CHANGED
|
@@ -4,24 +4,37 @@ LaunchChair Agent packages the LaunchChair CLI, MCP bridge, local bridge, and ru
|
|
|
4
4
|
|
|
5
5
|
Use it when you want an agent to create or discover LaunchChair projects, run product phases, continue project loops, pick up `Run with agent` jobs from LaunchChair, or expose LaunchChair tools through MCP.
|
|
6
6
|
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
From this package directory:
|
|
7
|
+
## Install or update
|
|
10
8
|
|
|
11
9
|
```bash
|
|
12
|
-
npm
|
|
13
|
-
|
|
14
|
-
launchchair help
|
|
10
|
+
npm install -g @launchchair/agent@latest
|
|
11
|
+
launchchair --version
|
|
15
12
|
launchchair doctor
|
|
16
13
|
```
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
Version 0.5.1 adds tabbed MCP Apps widgets for saved choices, rich phase synthesis, and Product/Feature validation scorecards to the expanded MCP, browser login, private token management, host-agent execution, idea preservation, and optional validation gates. Existing installations must update the package and restart their MCP connection to load the new tools.
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
launchchair
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
After updating, run `launchchair setup codex --skip-login` or `launchchair setup claude --skip-login` to refresh the installed path and verify tool discovery. Then restart/reload that client. Your saved account login and project bindings remain in `~/.launchchair/config.json`. Older tokens still work within their existing scopes; run `launchchair login` again with workspace-owner approval if you need the new `tokens.manage` scope.
|
|
18
|
+
|
|
19
|
+
For local release testing, run `npm pack ./packages/launchchair-agent --pack-destination /tmp` from the repository root and install the resulting tarball into an isolated npm prefix before publishing.
|
|
20
|
+
|
|
21
|
+
## Agent response widgets
|
|
22
|
+
|
|
23
|
+
The bridge supports LaunchChair AUX through MCP Apps. Three read-only tools return tabbed widgets using the app's Chakra theme, shared choice cards, and existing strategic scorecards:
|
|
24
|
+
|
|
25
|
+
- `launchchair_show_choices` (`projectId`, `phaseKey`, `bucketKey`): generated options and the saved choice.
|
|
26
|
+
- `launchchair_show_phase_synthesis` (`projectId`, `phaseKey`): the app's phase-specific synthesis cards, native tabs and charts, with verified completion state.
|
|
27
|
+
- `launchchair_show_validation_scores` (`projectId`): validation scorecards, evidence inputs, and separate direction scores for Product and Feature projects.
|
|
28
|
+
|
|
29
|
+
Every widget includes **Next action** controls. Saving a choice calls the existing `launchchair_select_choice` tool, then rereads the saved selection. Continue/review actions send a message to the host agent; the host executes queued prompts with its tools. The iframe never receives a token or calls the API directly. Existing scopes, entitlements, idea policies, validation gates, and downstream resets still apply.
|
|
30
|
+
|
|
31
|
+
The content pane scrolls at 560px on desktop and 440px on smaller screens using the app's scrollbar styles. The next-action footer stays outside that pane. Selected choices reuse the same choice cards, and validation thresholds live inside the scorecard footer. Synthesis reads the sanitized spec through the existing export permission; competitor editing and workspace notes remain in the authenticated app.
|
|
32
|
+
|
|
33
|
+
Rendering uses `_meta.ui.resourceUri`, `text/html;profile=mcp-app` resources, and the MCP Apps JSON-RPC host bridge. Compatible ChatGPT hosts can also use the feature-detected `window.openai` aliases. Text-only clients receive the full structured result and URLs. Static templates can be discovered while logged out; project reads still require authentication.
|
|
34
|
+
|
|
35
|
+
From the repository root, run `npm run agent:widgets:build` after changing widget components or the theme. This rebuilds the self-contained HTML in both bridge distributions. `npm run agent:widgets:preview -- /absolute/path/examples.html` builds interactive local examples with labeled sample data. Nothing is published by these commands.
|
|
36
|
+
|
|
37
|
+
The choice widget requires the bucket API's additive `choice` fields. Synthesis requests the existing export endpoint with `?format=json`; default Markdown downloads are unchanged. Test against a matching local API before releasing. Release the matching API changes before publishing the bridge package so installed clients can read the new choice and synthesis payloads.
|
|
25
38
|
|
|
26
39
|
## Login
|
|
27
40
|
|
|
@@ -49,7 +62,7 @@ Tokens are masked in CLI output. Do not paste real tokens into public docs, scre
|
|
|
49
62
|
|
|
50
63
|
## Guided Setup
|
|
51
64
|
|
|
52
|
-
Use `setup` as the easiest path. It starts browser login when no token is saved yet, writes the global MCP config for your agent, creates isolated per-project workspaces, and then
|
|
65
|
+
Use `setup` as the easiest path. It starts browser login when no token is saved yet, writes the global MCP config for your agent, creates isolated per-project workspaces, and then verifies MCP discovery and an authenticated status call before reporting authenticated success. Unauthenticated discovery is reported separately as login required.
|
|
53
66
|
|
|
54
67
|
Codex Desktop:
|
|
55
68
|
|
|
@@ -118,6 +131,29 @@ launchchair mcp-config claude
|
|
|
118
131
|
launchchair install-agent-md --cwd /absolute/path/to/repo
|
|
119
132
|
```
|
|
120
133
|
|
|
134
|
+
## Use any MCP tool from the terminal
|
|
135
|
+
|
|
136
|
+
`tools` discovers the same catalog as your MCP connection (47 tools when authenticated). `call` uses the bundled MCP implementation, including its login, permission checks, private credential storage, and host-execution defaults. Tool errors return a nonzero exit status and preserve details such as an upgrade URL.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
launchchair tools --json
|
|
140
|
+
launchchair call status
|
|
141
|
+
launchchair call next_step --json '{"projectId":"PROJECT_UUID"}'
|
|
142
|
+
launchchair call complete_run --input completed-run.json
|
|
143
|
+
launchchair call list_tokens
|
|
144
|
+
launchchair call create_token --json '{"name":"Build agent","scopes":["spec.read"]}'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Tool names work with or without the `launchchair_` prefix. Use `--input -` to read JSON arguments from stdin. `next_step` returns a claimed prompt for your current agent to execute with its connected plugins; it does not start another agent. `complete_run` submits the actual result and execution evidence. Token creation returns a private credential-file path, never the secret in terminal output.
|
|
148
|
+
|
|
149
|
+
Project creation preserves a supplied idea by default, even when validation is low. Only request exploration and a score gate when that matches the user's intent:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
launchchair create --name "Groomer candidate" --one-liner "Reduce missed appointments" --idea-intent explore --validation-gate very_high --save-project
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The gate requires pain >=85, opportunity >=85, and saturation <=30 before build/setup. For custom thresholds or the full Feature input schema, use `launchchair call create_project` or `launchchair call create_feature_project` with JSON arguments.
|
|
156
|
+
|
|
121
157
|
Feature projects can be created and planned from the CLI for every authenticated LaunchChair workspace:
|
|
122
158
|
|
|
123
159
|
```bash
|
|
@@ -158,7 +194,7 @@ launchchair mcp-config claude
|
|
|
158
194
|
|
|
159
195
|
The recommended config launches the MCP server through the exact Node executable and CLI file path generated by `launchchair setup` or `launchchair mcp-config`. It also pins `LAUNCHCHAIR_CONFIG_DIR` to the exact directory used by `launchchair login`, so Codex and Claude users do not need to paste tokens into MCP config after browser login—even when the desktop app starts with a different home or shell environment. The server uses standard newline-delimited JSON-RPC over stdio, as required by MCP clients.
|
|
160
196
|
|
|
161
|
-
Use `LAUNCHCHAIR_AGENT_TOKEN`
|
|
197
|
+
Use `LAUNCHCHAIR_AGENT_TOKEN` as a manual fallback when you skip `launchchair login` or your desktop app cannot read the saved config. A saved browser login takes precedence over stale environment credentials. Logout disables both CLI and MCP authentication until another login. For a separate per-client account, use a separate `LAUNCHCHAIR_CONFIG_DIR`. If you use a desktop custom MCP form, run `launchchair mcp-config codex --ui-fields` or `launchchair mcp-config claude --ui-fields` and paste the printed command, each argument, env vars, and working directory exactly as shown.
|
|
162
198
|
|
|
163
199
|
## Local Bridge
|
|
164
200
|
|
|
@@ -207,3 +243,15 @@ This package includes `AGENTS.md`. Fresh Codex, Claude, and Hermes chats should
|
|
|
207
243
|
- MCP docs: https://www.launchchair.io/docs/mcp
|
|
208
244
|
- Agent API docs: https://www.launchchair.io/docs/agent-api
|
|
209
245
|
- Machine-readable catalog: https://www.launchchair.io/api/agent/v1/docs
|
|
246
|
+
|
|
247
|
+
## MCP login and host execution
|
|
248
|
+
|
|
249
|
+
The MCP can start without a token. Call `launchchair_login`, show the returned LaunchChair approval URL, and call `launchchair_login_status` after approval. Respect its poll interval. Tokens are stored privately in the local config and never returned to the conversation. Existing tokens need a fresh owner-approved login for `tokens.manage`. Use `launchchair_create_token` to save a scoped credential file, `launchchair_list_tokens` for redacted metadata, and `launchchair_revoke_token`/`launchchair_logout` for cleanup.
|
|
250
|
+
|
|
251
|
+
Prefer `launchchair_next_step`, execute the claimed prompt in the current agent with its already-connected plugins, call `launchchair_complete_run`, and repeat. Do not spawn another model or local CLI unless explicitly requested (`executionMode=local_runner`). A waiting run is already claimed; poll it instead of executing it twice. Inspect forms/checklists with `launchchair_get_bucket`, save allowed patches with `launchchair_update_bucket`, and supply factual `executionEvidence` for setup and verification. Use `launchchair_get_starter` after validation to read the starter files and the host's GitHub/Vercel/Supabase tools to create and deploy the user's app. Bind the verified clone with `launchchair_bind_repository`. Use `stopPhaseKey=launch_sales` for the complete Product workflow.
|
|
252
|
+
|
|
253
|
+
Preserve a supplied idea and specified requirements, even with low validation scores. `ideaIntent=preserve` is the default. Report risks and continue the requested work when no score gate was requested; never pivot merely to improve a score. Choose a generated direction consistent with the supplied idea. Only use `ideaIntent=explore` for explicit discovery or pivot requests.
|
|
254
|
+
|
|
255
|
+
For “do not build until VERY high validation,” create candidates with `validationGate=very_high` (pain >=85, opportunity >=85, saturation <=30), validate through `market_validation`, and compare with `launchchair_compare_projects`. The gate is enforced on LaunchChair build/setup actions and cannot be weakened through generic mutations. Do not provision external resources until it passes. If no candidate qualifies, report the unmet thresholds honestly. Scores are research estimates, not a guarantee of market demand. Do not fabricate evidence or replace validation scores with direction-option scores.
|
|
256
|
+
|
|
257
|
+
Research sources, competitor notes, Pexels assets, logo upload, form/checklist data, prompts, build cards, run management, and markdown exports are available as MCP tools. Tool descriptions distinguish data writes from actual external execution. Existing user authorization carries forward; ask only at a genuine missing authorization or information boundary.
|
package/launchchair-cli.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
unbindProjectWorkspace,
|
|
21
21
|
} from "./project-workspace.mjs";
|
|
22
22
|
|
|
23
|
-
const VERSION = "0.
|
|
23
|
+
const VERSION = "0.5.1";
|
|
24
24
|
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
const DEFAULT_BASE_URL = "https://www.launchchair.io";
|
|
26
26
|
const CONFIG_DIR = process.env.LAUNCHCHAIR_CONFIG_DIR?.trim()
|
|
@@ -109,10 +109,16 @@ function configValue(key, envNames = [], fallback = "") {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
function token() {
|
|
112
|
+
const config = loadConfig();
|
|
113
|
+
if (config.mcpLoggedOut === true) return "";
|
|
114
|
+
if (config.mcpPreferSavedToken === true && config.agentToken) return config.agentToken;
|
|
112
115
|
return configValue("agentToken", ["LAUNCHCHAIR_AGENT_TOKEN", "LAUNCHCHAIR_API_KEY"]);
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
function tokenSource() {
|
|
119
|
+
const config = loadConfig();
|
|
120
|
+
if (config.mcpLoggedOut === true) return "logged out";
|
|
121
|
+
if (config.mcpPreferSavedToken === true && config.agentToken) return CONFIG_PATH;
|
|
116
122
|
if (env("LAUNCHCHAIR_AGENT_TOKEN")) return "LAUNCHCHAIR_AGENT_TOKEN";
|
|
117
123
|
if (env("LAUNCHCHAIR_API_KEY")) return "LAUNCHCHAIR_API_KEY";
|
|
118
124
|
if (loadConfig().agentToken) return CONFIG_PATH;
|
|
@@ -171,6 +177,7 @@ Use MCP-only when you want agent tools inside Codex/Claude/Hermes.
|
|
|
171
177
|
Use CLI + MCP when you also want quick terminal commands, diagnostics, and bridge control.
|
|
172
178
|
|
|
173
179
|
Commands:
|
|
180
|
+
--version Show the installed package version
|
|
174
181
|
doctor Check token, docs, API reachability, and local bridge files
|
|
175
182
|
login [--token TOKEN] Open browser login and save a LaunchChair Agent API token locally
|
|
176
183
|
logout Remove the saved local token
|
|
@@ -183,6 +190,9 @@ Commands:
|
|
|
183
190
|
run-once Claim and run one queued LaunchChair job through the local bridge
|
|
184
191
|
bridge Start the long-running local bridge for Run with Agent
|
|
185
192
|
mcp-server Run the stdio MCP server using saved CLI config
|
|
193
|
+
tools [--json] List the available MCP tools and their input schemas
|
|
194
|
+
call TOOL [--json JSON|--input FILE]
|
|
195
|
+
Call any MCP tool; JSON output, nonzero exit on tool errors
|
|
186
196
|
setup codex|claude|claude-desktop|claude-code|terminal [options]
|
|
187
197
|
Guided global CLI/MCP setup with isolated project workspaces
|
|
188
198
|
bind --project-id ID --cwd PATH Bind one LaunchChair project to a verified local Git clone
|
|
@@ -202,6 +212,8 @@ Create options:
|
|
|
202
212
|
--start-loop
|
|
203
213
|
--save-project Save the created project id as the CLI default
|
|
204
214
|
--idempotency-key KEY
|
|
215
|
+
--idea-intent preserve|explore Default: preserve the supplied idea, even with low scores
|
|
216
|
+
--validation-gate very_high Require pain >=85, opportunity >=85, saturation <=30 before build
|
|
205
217
|
|
|
206
218
|
Feature create options:
|
|
207
219
|
--project-kind feature
|
|
@@ -245,7 +257,7 @@ Login options:
|
|
|
245
257
|
--timeout SECONDS Default: 600
|
|
246
258
|
|
|
247
259
|
Env:
|
|
248
|
-
LAUNCHCHAIR_AGENT_TOKEN Optional
|
|
260
|
+
LAUNCHCHAIR_AGENT_TOKEN Optional token fallback when no saved login takes precedence
|
|
249
261
|
LAUNCHCHAIR_BASE_URL Default: https://www.launchchair.io
|
|
250
262
|
LAUNCHCHAIR_PROJECT_ID Optional default project id
|
|
251
263
|
LC_AGENT_CODEX_CWD Legacy candidate only; verified per project before use
|
|
@@ -255,6 +267,11 @@ MCP config options:
|
|
|
255
267
|
--ui-fields Print fields for Codex Desktop's custom MCP form
|
|
256
268
|
--copy-config Copy generated output to clipboard on macOS
|
|
257
269
|
|
|
270
|
+
Tool call options:
|
|
271
|
+
--json JSON Tool arguments as a JSON object; defaults to {}
|
|
272
|
+
--input FILE Read tool arguments from a JSON file; use - for stdin
|
|
273
|
+
--timeout SECONDS Request timeout. Default: 60, max: 3600
|
|
274
|
+
|
|
258
275
|
Config:
|
|
259
276
|
${CONFIG_PATH}
|
|
260
277
|
`);
|
|
@@ -308,7 +325,13 @@ async function api(pathname, options = {}) {
|
|
|
308
325
|
if (!response.ok) {
|
|
309
326
|
const retryAfter = response.headers.get("retry-after");
|
|
310
327
|
const suffix = retryAfter ? ` Retry after ${retryAfter}s.` : "";
|
|
311
|
-
|
|
328
|
+
const next = body?.upgradeUrl
|
|
329
|
+
? ` Upgrade: ${body.upgradeUrl}`
|
|
330
|
+
: response.status === 401 ? " Run launchchair login to reconnect." : "";
|
|
331
|
+
const error = new Error(`${body?.error ?? response.statusText}${suffix}${next}`);
|
|
332
|
+
error.status = response.status;
|
|
333
|
+
error.retryAfterSeconds = Number(retryAfter) || 10;
|
|
334
|
+
throw error;
|
|
312
335
|
}
|
|
313
336
|
return body;
|
|
314
337
|
}
|
|
@@ -331,7 +354,10 @@ async function publicApi(pathname, options = {}) {
|
|
|
331
354
|
if (!response.ok) {
|
|
332
355
|
const retryAfter = response.headers.get("retry-after");
|
|
333
356
|
const suffix = retryAfter ? ` Retry after ${retryAfter}s.` : "";
|
|
334
|
-
|
|
357
|
+
const error = new Error(`${body?.error ?? response.statusText}${suffix}`);
|
|
358
|
+
error.status = response.status;
|
|
359
|
+
error.retryAfterSeconds = Number(retryAfter) || 10;
|
|
360
|
+
throw error;
|
|
335
361
|
}
|
|
336
362
|
return body;
|
|
337
363
|
}
|
|
@@ -391,6 +417,8 @@ async function login(args) {
|
|
|
391
417
|
}
|
|
392
418
|
saveConfig({
|
|
393
419
|
agentToken: incomingToken,
|
|
420
|
+
mcpLoggedOut: false,
|
|
421
|
+
mcpPreferSavedToken: true,
|
|
394
422
|
baseUrl: incomingBaseUrl ?? baseUrl(),
|
|
395
423
|
projectId: incomingProjectId || defaultProjectId() || undefined,
|
|
396
424
|
});
|
|
@@ -434,7 +462,7 @@ async function login(args) {
|
|
|
434
462
|
|
|
435
463
|
const timeoutSeconds =
|
|
436
464
|
typeof args.timeout === "string" && Number.isFinite(Number(args.timeout)) ? Math.max(10, Number(args.timeout)) : Number(start.expiresIn ?? 600);
|
|
437
|
-
|
|
465
|
+
let intervalSeconds = Math.max(5, Number(start.interval ?? 5));
|
|
438
466
|
const startedAt = Date.now();
|
|
439
467
|
print("");
|
|
440
468
|
print("Waiting for approval. Leave this terminal open.");
|
|
@@ -449,10 +477,12 @@ async function login(args) {
|
|
|
449
477
|
});
|
|
450
478
|
} catch (error) {
|
|
451
479
|
const message = error instanceof Error ? error.message : String(error);
|
|
480
|
+
if (error.status === 429) { intervalSeconds = Math.max(5, error.retryAfterSeconds); continue; }
|
|
452
481
|
if (/pending/i.test(message)) continue;
|
|
453
482
|
throw error;
|
|
454
483
|
}
|
|
455
484
|
if (poll?.status === "pending") {
|
|
485
|
+
intervalSeconds = Math.max(5, Number(poll.interval) || intervalSeconds);
|
|
456
486
|
write(paint(".", "dim"));
|
|
457
487
|
continue;
|
|
458
488
|
}
|
|
@@ -460,6 +490,8 @@ async function login(args) {
|
|
|
460
490
|
print("");
|
|
461
491
|
saveConfig({
|
|
462
492
|
agentToken: poll.token,
|
|
493
|
+
mcpLoggedOut: false,
|
|
494
|
+
mcpPreferSavedToken: true,
|
|
463
495
|
baseUrl: baseUrl(),
|
|
464
496
|
projectId: incomingProjectId || defaultProjectId() || undefined,
|
|
465
497
|
});
|
|
@@ -478,11 +510,12 @@ async function login(args) {
|
|
|
478
510
|
}
|
|
479
511
|
|
|
480
512
|
function logout() {
|
|
481
|
-
deleteConfigKeys(["agentToken"]);
|
|
513
|
+
deleteConfigKeys(["agentToken", "pendingMcpLogin"]);
|
|
514
|
+
saveConfig({ mcpLoggedOut: true });
|
|
482
515
|
title("CLI logout");
|
|
483
516
|
ok(`Removed saved token from ${CONFIG_PATH}`);
|
|
484
517
|
if (env("LAUNCHCHAIR_AGENT_TOKEN") || env("LAUNCHCHAIR_API_KEY")) {
|
|
485
|
-
warn("An environment token is still set
|
|
518
|
+
warn("An environment token is still set; it remains ignored until you log in again.");
|
|
486
519
|
}
|
|
487
520
|
}
|
|
488
521
|
|
|
@@ -606,6 +639,14 @@ async function createProject(args) {
|
|
|
606
639
|
throw new Error("--project-kind must be product or feature.");
|
|
607
640
|
}
|
|
608
641
|
const featureProject = projectKind === "feature";
|
|
642
|
+
const ideaIntent = args["idea-intent"] ?? "preserve";
|
|
643
|
+
if (!["preserve", "explore"].includes(ideaIntent)) {
|
|
644
|
+
throw new Error("--idea-intent must be preserve or explore.");
|
|
645
|
+
}
|
|
646
|
+
const validationGate = args["validation-gate"];
|
|
647
|
+
if (validationGate !== undefined && validationGate !== "very_high") {
|
|
648
|
+
throw new Error("--validation-gate must be very_high. For custom thresholds, use launchchair call create_project --input FILE.");
|
|
649
|
+
}
|
|
609
650
|
const featureDescription = String(args["feature-description"] ?? args["one-liner"] ?? "").trim();
|
|
610
651
|
const featureProblem = String(args.problem ?? "").trim();
|
|
611
652
|
if (featureProject && (!featureDescription || !featureProblem)) {
|
|
@@ -664,7 +705,7 @@ async function createProject(args) {
|
|
|
664
705
|
const body = await api("/api/agent/v1/projects", {
|
|
665
706
|
method: "POST",
|
|
666
707
|
headers,
|
|
667
|
-
body: JSON.stringify(requestBody),
|
|
708
|
+
body: JSON.stringify({ ...requestBody, ideaIntent, validationGate }),
|
|
668
709
|
});
|
|
669
710
|
const projectId = body?.project?.id ?? body?.projectId ?? "";
|
|
670
711
|
title("Project created");
|
|
@@ -876,6 +917,100 @@ function spawnMcpServer(extraArgs = []) {
|
|
|
876
917
|
});
|
|
877
918
|
}
|
|
878
919
|
|
|
920
|
+
// Use the bundled MCP so terminal calls share its login, scope checks, and host workflow.
|
|
921
|
+
async function requestMcp(method, params, timeoutMs = 60_000) {
|
|
922
|
+
const child = spawn(process.execPath, [path.join(SCRIPT_DIR, "mcp-bridge-server.mjs")], {
|
|
923
|
+
env: buildBridgeEnv(),
|
|
924
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
925
|
+
});
|
|
926
|
+
let buffer = "";
|
|
927
|
+
let serial = 0;
|
|
928
|
+
const pending = new Map();
|
|
929
|
+
const failPending = (error) => {
|
|
930
|
+
for (const entry of pending.values()) { clearTimeout(entry.timer); entry.reject(error); }
|
|
931
|
+
pending.clear();
|
|
932
|
+
};
|
|
933
|
+
child.on("error", failPending);
|
|
934
|
+
child.on("exit", (code) => failPending(new Error(`MCP server exited before replying (code ${code ?? "unknown"}).`)));
|
|
935
|
+
child.stdin.on("error", failPending);
|
|
936
|
+
child.stderr.on("data", (chunk) => process.stderr.write(chunk));
|
|
937
|
+
child.stdout.setEncoding("utf8");
|
|
938
|
+
child.stdout.on("data", (chunk) => {
|
|
939
|
+
buffer += chunk;
|
|
940
|
+
let newline;
|
|
941
|
+
while ((newline = buffer.indexOf("\n")) !== -1) {
|
|
942
|
+
const line = buffer.slice(0, newline).trim();
|
|
943
|
+
buffer = buffer.slice(newline + 1);
|
|
944
|
+
if (!line) continue;
|
|
945
|
+
let message;
|
|
946
|
+
try { message = JSON.parse(line); }
|
|
947
|
+
catch { failPending(new Error("MCP server returned invalid JSON.")); return; }
|
|
948
|
+
const entry = pending.get(message.id);
|
|
949
|
+
if (!entry) continue;
|
|
950
|
+
pending.delete(message.id);
|
|
951
|
+
clearTimeout(entry.timer);
|
|
952
|
+
if (message.error) entry.reject(new Error(message.error.message || "MCP request failed."));
|
|
953
|
+
else entry.resolve(message.result);
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
const rpc = (rpcMethod, rpcParams) => new Promise((resolve, reject) => {
|
|
957
|
+
const id = ++serial;
|
|
958
|
+
const timer = setTimeout(() => {
|
|
959
|
+
pending.delete(id);
|
|
960
|
+
reject(new Error("MCP request timed out. Check the project's run status before retrying a write."));
|
|
961
|
+
}, timeoutMs);
|
|
962
|
+
pending.set(id, { resolve, reject, timer });
|
|
963
|
+
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method: rpcMethod, params: rpcParams })}\n`);
|
|
964
|
+
});
|
|
965
|
+
try {
|
|
966
|
+
await rpc("initialize", { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "launchchair-cli", version: VERSION } });
|
|
967
|
+
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" })}\n`);
|
|
968
|
+
return await rpc(method, params);
|
|
969
|
+
} finally {
|
|
970
|
+
child.stdin.end();
|
|
971
|
+
child.kill();
|
|
972
|
+
failPending(new Error("MCP client closed."));
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
async function listTools(args) {
|
|
977
|
+
const result = await requestMcp("tools/list", {});
|
|
978
|
+
if (args.json === true) return print(JSON.stringify(result, null, 2));
|
|
979
|
+
title("MCP tools");
|
|
980
|
+
for (const tool of result.tools ?? []) print(`${tool.name}\n ${tool.description}`);
|
|
981
|
+
print("\nUse launchchair tools --json for input schemas, then launchchair call TOOL --json '{...}'.");
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
async function callTool(args) {
|
|
985
|
+
const requestedName = args._[0];
|
|
986
|
+
if (!requestedName) throw new Error("call requires a tool name. Run launchchair tools to list them.");
|
|
987
|
+
if (args.json !== undefined && args.input !== undefined) throw new Error("Use either --json or --input, not both.");
|
|
988
|
+
let input = "{}";
|
|
989
|
+
if (args.json !== undefined) {
|
|
990
|
+
if (typeof args.json !== "string") throw new Error("--json requires a JSON object.");
|
|
991
|
+
input = args.json;
|
|
992
|
+
} else if (args.input !== undefined) {
|
|
993
|
+
if (typeof args.input !== "string") throw new Error("--input requires a file path or - for stdin.");
|
|
994
|
+
input = readFileSync(args.input === "-" ? 0 : path.resolve(args.input), "utf8");
|
|
995
|
+
}
|
|
996
|
+
let toolArgs;
|
|
997
|
+
try { toolArgs = JSON.parse(input); }
|
|
998
|
+
catch { throw new Error("Tool arguments must be valid JSON."); }
|
|
999
|
+
if (!toolArgs || typeof toolArgs !== "object" || Array.isArray(toolArgs)) throw new Error("Tool arguments must be a JSON object.");
|
|
1000
|
+
const timeoutSeconds = args.timeout === undefined ? 60 : Number(args.timeout);
|
|
1001
|
+
if (typeof args.timeout === "boolean" || !Number.isFinite(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > 3600) {
|
|
1002
|
+
throw new Error("--timeout must be between 1 and 3600 seconds.");
|
|
1003
|
+
}
|
|
1004
|
+
const result = await requestMcp("tools/call", {
|
|
1005
|
+
name: requestedName.startsWith("launchchair_") ? requestedName : `launchchair_${requestedName}`,
|
|
1006
|
+
arguments: toolArgs,
|
|
1007
|
+
}, timeoutSeconds * 1000);
|
|
1008
|
+
// LaunchChair tools return one JSON text block. Keep other MCP content intact.
|
|
1009
|
+
print(result.content?.length === 1 && result.content[0].type === "text"
|
|
1010
|
+
? result.content[0].text : JSON.stringify(result, null, 2));
|
|
1011
|
+
if (result.isError) process.exitCode = 1;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
879
1014
|
function normalizedMcpTarget(target) {
|
|
880
1015
|
return targetDetails(target || "codex").mcpTarget || "codex";
|
|
881
1016
|
}
|
|
@@ -885,13 +1020,11 @@ function tomlString(value) {
|
|
|
885
1020
|
}
|
|
886
1021
|
|
|
887
1022
|
function mcpEnvForTarget(target, options = {}) {
|
|
888
|
-
const includeTokenPlaceholder = options.includeTokenPlaceholder !== false;
|
|
889
1023
|
const details = targetDetails(target || "codex");
|
|
890
1024
|
const projectId = defaultProjectId();
|
|
891
1025
|
const envBlock = {
|
|
892
1026
|
LAUNCHCHAIR_BASE_URL: baseUrl(),
|
|
893
1027
|
LAUNCHCHAIR_CONFIG_DIR: CONFIG_DIR,
|
|
894
|
-
...(token() || !includeTokenPlaceholder ? {} : { LAUNCHCHAIR_AGENT_TOKEN: "<optional full lc_at token when launchchair login was not used>" }),
|
|
895
1028
|
...(projectId ? { LAUNCHCHAIR_PROJECT_ID: projectId } : {}),
|
|
896
1029
|
LC_AGENT_ROUTER_GPT_TARGET: details.routerTarget,
|
|
897
1030
|
LC_AGENT_ROUTER_CODEX_TARGET: details.routerTarget,
|
|
@@ -916,6 +1049,7 @@ function verifyMcpServer(target, timeoutMs = 20_000) {
|
|
|
916
1049
|
stdio: ["pipe", "pipe", "pipe"],
|
|
917
1050
|
});
|
|
918
1051
|
let settled = false;
|
|
1052
|
+
let discoveredTools = [];
|
|
919
1053
|
let stdout = "";
|
|
920
1054
|
let stderr = "";
|
|
921
1055
|
|
|
@@ -966,13 +1100,29 @@ function verifyMcpServer(target, timeoutMs = 20_000) {
|
|
|
966
1100
|
const toolNames = Array.isArray(response?.result?.tools)
|
|
967
1101
|
? response.result.tools.map((tool) => String(tool?.name || "")).filter(Boolean)
|
|
968
1102
|
: [];
|
|
969
|
-
const requiredTools = [
|
|
1103
|
+
const requiredTools = [
|
|
1104
|
+
"launchchair_status", "launchchair_create_project", "launchchair_list_projects",
|
|
1105
|
+
"launchchair_login", "launchchair_login_status", "launchchair_create_token",
|
|
1106
|
+
"launchchair_next_step", "launchchair_complete_run", "launchchair_get_validation_gate",
|
|
1107
|
+
"launchchair_update_bucket", "launchchair_get_starter", "launchchair_export_mvp_spec",
|
|
1108
|
+
];
|
|
970
1109
|
const missingTools = requiredTools.filter((name) => !toolNames.includes(name));
|
|
971
1110
|
if (missingTools.length) {
|
|
972
1111
|
finish(new Error(`MCP verification did not discover required tools: ${missingTools.join(", ")}`));
|
|
973
1112
|
return;
|
|
974
1113
|
}
|
|
975
|
-
|
|
1114
|
+
discoveredTools = toolNames;
|
|
1115
|
+
if (!token()) { finish(null, toolNames); continue; }
|
|
1116
|
+
send({ jsonrpc: "2.0", id: 3, method: "tools/call", params: { name: "launchchair_status", arguments: {} } });
|
|
1117
|
+
}
|
|
1118
|
+
if (response?.id === 3) {
|
|
1119
|
+
let status = {};
|
|
1120
|
+
try { status = JSON.parse(response.result?.content?.[0]?.text || "{}"); } catch {}
|
|
1121
|
+
if (response.error || response.result?.isError || status.authenticated !== true) {
|
|
1122
|
+
finish(new Error(`MCP authentication verification failed: ${status.error || response.error?.message || "not authenticated"}`));
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
finish(null, discoveredTools);
|
|
976
1126
|
}
|
|
977
1127
|
}
|
|
978
1128
|
});
|
|
@@ -1286,7 +1436,10 @@ function installLaunchChairSkill(args) {
|
|
|
1286
1436
|
"# LaunchChair workflow",
|
|
1287
1437
|
"",
|
|
1288
1438
|
"Use the installed LaunchChair MCP tools before web search or local repo discovery for LaunchChair project work.",
|
|
1289
|
-
"Call launchchair_status if capability context is unclear.",
|
|
1439
|
+
"Call launchchair_status if capability context is unclear. If login is required, use launchchair_login and launchchair_login_status; never print token secrets.",
|
|
1440
|
+
"Prefer launchchair_next_step and execute its claimed prompt in this host agent using existing plugins, then complete_run. Use local runners only when explicitly requested.",
|
|
1441
|
+
"Preserve supplied ideas and requirements even when validation is low. ideaIntent=preserve is the default; exploration and pivots require an explicit user request.",
|
|
1442
|
+
"Only impose a validation gate when requested. VERY high means validationGate=very_high (pain>=85, opportunity>=85, saturation<=30). Never fabricate evidence or weaken the gate.",
|
|
1290
1443
|
"For a new product, use launchchair_create_project.",
|
|
1291
1444
|
"For a feature in an existing product, use launchchair_create_feature_project. Never substitute a Product project if that tool is unavailable; report the setup or authentication issue instead.",
|
|
1292
1445
|
"Use planToBuildBoard=true for planning through the Feature build board.",
|
|
@@ -1326,6 +1479,8 @@ async function setup(args) {
|
|
|
1326
1479
|
}
|
|
1327
1480
|
saveConfig({
|
|
1328
1481
|
agentToken: incomingToken,
|
|
1482
|
+
mcpLoggedOut: false,
|
|
1483
|
+
mcpPreferSavedToken: true,
|
|
1329
1484
|
baseUrl: incomingBaseUrl ?? baseUrl(),
|
|
1330
1485
|
projectId: incomingProjectId || defaultProjectId() || undefined,
|
|
1331
1486
|
});
|
|
@@ -1412,11 +1567,11 @@ async function setup(args) {
|
|
|
1412
1567
|
}
|
|
1413
1568
|
}
|
|
1414
1569
|
|
|
1415
|
-
if (!details.terminalOnly &&
|
|
1570
|
+
if (!details.terminalOnly && args["skip-mcp-check"] !== true) {
|
|
1416
1571
|
const toolNames = await verifyMcpServer(details.mcpTarget);
|
|
1417
1572
|
print("");
|
|
1418
|
-
title("MCP verification passed");
|
|
1419
|
-
ok(`
|
|
1573
|
+
title(token() ? "MCP verification passed" : "MCP discovery verified — login required");
|
|
1574
|
+
ok(`Discovered ${toolNames.length} LaunchChair tools.${token() ? " Authenticated status verified." : " Call launchchair_login in your agent."}`);
|
|
1420
1575
|
} else if (!details.terminalOnly && !token()) {
|
|
1421
1576
|
warn("MCP verification was skipped because no LaunchChair token is configured.");
|
|
1422
1577
|
} else if (!details.terminalOnly && args["skip-mcp-check"] === true) {
|
|
@@ -1455,7 +1610,8 @@ async function setup(args) {
|
|
|
1455
1610
|
print(`2. Restart or reload ${details.label} so the MCP server is exposed to fresh chats.`);
|
|
1456
1611
|
}
|
|
1457
1612
|
print("Use the generated command and argument fields exactly as printed; setup resolves the local Node and CLI paths for this machine.");
|
|
1458
|
-
print("
|
|
1613
|
+
print("Your agent can use launchchair_next_step and launchchair_complete_run with its connected plugins.");
|
|
1614
|
+
print("For unattended local-runner jobs queued from LaunchChair's Run with agent button, optionally run:");
|
|
1459
1615
|
print(` ${paint("launchchair bridge", "cyan")}`);
|
|
1460
1616
|
print("Start a fresh agent chat. The agent should discover the LaunchChair MCP tools automatically.");
|
|
1461
1617
|
}
|
|
@@ -1479,6 +1635,7 @@ async function main() {
|
|
|
1479
1635
|
const [command = "help", ...rest] = process.argv.slice(2);
|
|
1480
1636
|
const args = parseArgs(rest);
|
|
1481
1637
|
if (command === "help" || command === "--help" || command === "-h") return help();
|
|
1638
|
+
if (command === "--version" || command === "-v" || command === "version") return print(VERSION);
|
|
1482
1639
|
if (command === "doctor") return doctor();
|
|
1483
1640
|
if (command === "login") return login(args);
|
|
1484
1641
|
if (command === "logout") return logout();
|
|
@@ -1490,6 +1647,8 @@ async function main() {
|
|
|
1490
1647
|
if (command === "run-once") return spawnBridge(["--once", "--verbose"]);
|
|
1491
1648
|
if (command === "bridge") return spawnBridge(["--verbose"]);
|
|
1492
1649
|
if (command === "mcp-server") return spawnMcpServer();
|
|
1650
|
+
if (command === "tools") return listTools(args);
|
|
1651
|
+
if (command === "call") return callTool(args);
|
|
1493
1652
|
if (command === "setup") return setup(args);
|
|
1494
1653
|
if (command === "bind") return bindProject(args);
|
|
1495
1654
|
if (command === "unbind") return unbindProject(args);
|
package/local-bridge.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { fileURLToPath } from "node:url";
|
|
|
18
18
|
import { resolveProjectWorkspace } from "./project-workspace.mjs";
|
|
19
19
|
import { buildRunnerCommand, parseRunnerCommand } from "./runner-command.mjs";
|
|
20
20
|
|
|
21
|
-
const VERSION = "0.
|
|
21
|
+
const VERSION = "0.5.1";
|
|
22
22
|
const CLIENT_TYPES = ["codex", "chatgpt", "claude", "claude_code", "other"];
|
|
23
23
|
const AGENT_SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
const CONFIG_DIR = process.env.LAUNCHCHAIR_CONFIG_DIR?.trim()
|
|
@@ -402,6 +402,7 @@ async function executeRunner(run) {
|
|
|
402
402
|
stdio: ["pipe", "pipe", "pipe"],
|
|
403
403
|
env: {
|
|
404
404
|
...process.env,
|
|
405
|
+
...(resolved.workspace.source === "isolated" && run?.runnerWorkspace?.requiresRepository !== true ? { LC_AGENT_CODEX_SKIP_GIT_CHECK: "1" } : {}),
|
|
405
406
|
LC_AGENT_RUN_ID: String(run.id ?? ""),
|
|
406
407
|
LC_AGENT_PROJECT_ID: String(run.projectId ?? ""),
|
|
407
408
|
LC_AGENT_PHASE_KEY: String(run.phaseKey ?? ""),
|