@launchchair/agent 0.4.2 → 0.4.5

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"
@@ -139,6 +140,7 @@ If the desktop app cannot find `launchchair`, run `which launchchair` in Termina
139
140
  5. If the user clicked Run with agent in LaunchChair, call `launchchair_run_once`.
140
141
  6. If the user asks to advance the product workflow, call `launchchair_continue_project`.
141
142
  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.
143
+ 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.
142
144
 
143
145
  ## Consent Behavior
144
146
 
@@ -151,6 +153,8 @@ Safe LaunchChair MCP/API actions that should not need another user confirmation:
151
153
  - continuing a project loop with `launchchair_continue_project`
152
154
  - selecting a generated wedge, pricing, or feature direction with `launchchair_select_choice`
153
155
  - running/rerunning Product Ideation, Market Validation, Positioning, Pricing, and MVP Blueprint buckets
156
+ - running/rerunning Feature Definition and User & Feature Validation for score-based feature comparison
157
+ - reading Product or Feature validation scorecards with `launchchair_get_scorecards`
154
158
  - returning phase synthesis links and selected choices
155
159
 
156
160
  Stop and ask only when:
@@ -177,9 +181,12 @@ Do not start with `ls`, `rg`, dependency inspection, or nearby repo searches whe
177
181
  - LaunchChair project creation
178
182
  - LaunchChair phase loops
179
183
  - score-based reruns such as ICP Pain Score, Market Saturation Score, or Wedge Opportunity Score
184
+ - Feature score-based validation using Feature Pain Score, Pattern Saturation Score, and Feature Opportunity Score
180
185
 
181
186
  Those are LaunchChair project-state tasks, not local repo tasks.
182
187
 
188
+ For Feature projects, the three Feature validation scorecards evaluate the idea. The two generated wedge-direction scores rank the narrow opportunities inside that idea; they are not the Feature validation scores. User & Feature Validation selects the wedge first, then Feature Blueprint generates and selects exactly two concrete feature directions. Every wedge and Feature direction must be grounded in four evidence pillars: ICP complaint themes, delight themes, substitute behaviors, and competitor gaps. Never collapse those decisions or answer a request for Feature validation scores with direction-option scores alone. When comparing multiple Feature ideas, run each through User & Feature Validation, call `launchchair_get_scorecards` for each project, maximize Feature Pain and Feature Opportunity, minimize Pattern Saturation, and prefer ideas that pass every returned recommended threshold.
189
+
183
190
  ## When Repo Inspection Is Correct
184
191
 
185
192
  Inspect the repo when the current LaunchChair work is:
package/README.md CHANGED
@@ -94,6 +94,8 @@ launchchair setup claude --cwd /absolute/path/to/repo-or-empty-folder --write-co
94
94
  launchchair setup terminal --cwd /absolute/path/to/repo-or-empty-folder
95
95
  launchchair projects
96
96
  launchchair projects --query LeafLore
97
+ launchchair scorecards --project-id <project-id>
98
+ launchchair scorecards --project-name LeafLore
97
99
  launchchair create --name "SignalLift" --one-liner "Distribution workspace for technical founders" --project-type b2b --save-project
98
100
  launchchair continue --stop-phase-key market_validation
99
101
  launchchair continue --completion-target "rerun Product Ideation until ICP Pain Score is above 85"
@@ -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.4";
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()
@@ -159,6 +159,8 @@ Commands:
159
159
  logout Remove the saved local token
160
160
  whoami Show the current API identity and token source
161
161
  projects [--query name] List projects visible to the token
162
+ scorecards [--project-id ID|--project-name NAME]
163
+ Read Product or Feature validation scorecards
162
164
  create --name NAME [options] Create a LaunchChair project
163
165
  continue [--project-id ID] Ask LaunchChair to continue the project loop once
164
166
  run-once Claim and run one queued LaunchChair job through the local bridge
@@ -493,6 +495,86 @@ async function listProjects(args) {
493
495
  });
494
496
  }
495
497
 
498
+ function normalizeProjectName(value) {
499
+ return String(value ?? "")
500
+ .trim()
501
+ .toLowerCase()
502
+ .replace(/\s+/g, " ");
503
+ }
504
+
505
+ async function resolveProjectIdForCommand(args, commandName) {
506
+ const configuredProjectId = args["project-id"] || defaultProjectId();
507
+ if (configuredProjectId) return configuredProjectId;
508
+
509
+ const projectName = String(args["project-name"] ?? args.query ?? "").trim();
510
+ if (!projectName) {
511
+ throw new Error(
512
+ `${commandName} requires --project-id, --project-name, LAUNCHCHAIR_PROJECT_ID, or config set project-id.`,
513
+ );
514
+ }
515
+
516
+ const params = new URLSearchParams();
517
+ params.set("query", projectName);
518
+ params.set("limit", "10");
519
+ const body = await api(`/api/agent/v1/projects?${params.toString()}`);
520
+ const projects = Array.isArray(body?.projects) ? body.projects : [];
521
+ const normalizedName = normalizeProjectName(projectName);
522
+ const exactMatches = projects.filter((project) => normalizeProjectName(project?.name) === normalizedName);
523
+ const candidates = exactMatches.length > 0 ? exactMatches : projects;
524
+
525
+ if (candidates.length === 1 && candidates[0]?.id) {
526
+ return candidates[0].id;
527
+ }
528
+
529
+ if (candidates.length > 1) {
530
+ const labels = candidates
531
+ .map((project) => `${project?.name ?? "Untitled project"} (${project?.id ?? "no id"})`)
532
+ .join(", ");
533
+ throw new Error(`Could not resolve a unique project for "${projectName}". Matching projects: ${labels}.`);
534
+ }
535
+
536
+ throw new Error(`Could not find a project named "${projectName}" for this token.`);
537
+ }
538
+
539
+ async function showScorecards(args) {
540
+ const projectId = await resolveProjectIdForCommand(args, "scorecards");
541
+ const body = await api(`/api/agent/v1/projects/${encodeURIComponent(projectId)}/scorecards`);
542
+ title(`${body?.projectName ?? "Project"} validation scorecards`);
543
+ const scorecards = Array.isArray(body?.scorecards) ? body.scorecards : [];
544
+ if (!scorecards.length) {
545
+ warn("No validation scorecards returned.");
546
+ }
547
+ scorecards.forEach((scorecard) => {
548
+ const score = typeof scorecard?.score === "number" ? `${scorecard.score}/100` : "needs data";
549
+ const threshold = `${scorecard?.optimization === "minimize" ? "≤" : "≥"}${scorecard?.recommendedThreshold ?? "—"}`;
550
+ const tone = scorecard?.passesRecommendedThreshold === true ? "green" : scorecard?.score === null ? "yellow" : "red";
551
+ row(scorecard?.title ?? scorecard?.id ?? "Score", `${score} · target ${threshold}`, tone);
552
+ if (scorecard?.signalLabel) row("Signal", scorecard.signalLabel, "dim");
553
+ if (scorecard?.explanation) row("Why", scorecard.explanation, "dim");
554
+ if (scorecard?.score === null && scorecard?.insufficientDataMessage) {
555
+ row("Need", scorecard.insufficientDataMessage, "yellow");
556
+ }
557
+ if (scorecard?.score === null && Array.isArray(scorecard?.requiredPhases) && scorecard.requiredPhases.length > 0) {
558
+ row("Required phases", scorecard.requiredPhases.join(", "), "dim");
559
+ }
560
+ });
561
+ const thresholdMessage = body?.allScoresAvailable === false
562
+ ? "missing required phase data"
563
+ : body?.passesRecommendedThresholds
564
+ ? "all passed"
565
+ : "needs another validation pass";
566
+ row("Thresholds", thresholdMessage, body?.passesRecommendedThresholds ? "green" : "yellow");
567
+ if (body?.guidance?.distinction) row("Important", body.guidance.distinction, "dim");
568
+ const directions = Array.isArray(body?.directionOptions) ? body.directionOptions : [];
569
+ if (directions.length > 0) {
570
+ print("");
571
+ print(paint("Direction options (not validation scorecards)", "bold"));
572
+ directions.forEach((direction) => {
573
+ row(direction?.selected ? "Selected" : "Option", `${direction?.title ?? direction?.id}: ${direction?.score ?? 0}/100`, direction?.selected ? "cyan" : "dim");
574
+ });
575
+ }
576
+ }
577
+
496
578
  async function createProject(args) {
497
579
  const name = typeof args.name === "string" ? args.name : "";
498
580
  if (!name) {
@@ -1002,6 +1084,8 @@ function installLaunchChairSkill(args) {
1002
1084
  "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 beta-access issue instead.",
1003
1085
  "Use planToBuildBoard=true for planning through the Feature build board.",
1004
1086
  "Use fullLoop=true only when the user asks to implement/build the feature; continue agent-run QA and stop for production SQL or a genuine external authorization boundary.",
1087
+ "After Feature validation, call launchchair_get_scorecards. Feature Pain, Pattern Saturation, and Feature Opportunity are the validation scorecards; generated direction scores only rank directions inside the idea.",
1088
+ "When comparing multiple Feature ideas, require evidence across ICP complaint themes, delight themes, substitute behaviors, and competitor gaps; then evaluate each with the scorecards, maximize Feature Pain and Feature Opportunity, minimize Pattern Saturation, and prefer ideas that pass every returned recommended threshold.",
1005
1089
  ]
1006
1090
  : []),
1007
1091
  "Do not ask for extra confirmation for ordinary LaunchChair MCP calls when the user already requested the workflow and the token permits it.",
@@ -1165,6 +1249,7 @@ async function main() {
1165
1249
  if (command === "logout") return logout();
1166
1250
  if (command === "whoami") return whoami();
1167
1251
  if (command === "projects") return listProjects(args);
1252
+ if (command === "scorecards") return showScorecards(args);
1168
1253
  if (command === "create") return createProject(args);
1169
1254
  if (command === "continue") return continueProject(args);
1170
1255
  if (command === "run-once") return spawnBridge(["--once", "--verbose"]);
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.4";
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,16 +12,22 @@
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.4";
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
- "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.";
30
+ "Use LaunchChair MCP tools—not web browsing—for LaunchChair project discovery, creation, planning, validation scoring, and loops. Call the most specific available tool. When asked for validation scores, call launchchair_get_scorecards and report those scorecards; do not substitute generated direction-option scores. If a requested workflow is unavailable, explain the access or setup issue instead of silently substituting another project type or workflow.";
25
31
 
26
32
  function nodeScriptCommand(scriptName) {
27
33
  return `${JSON.stringify(process.execPath)} ${JSON.stringify(path.join(AGENT_SCRIPT_DIR, scriptName))}`;
@@ -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
 
@@ -388,6 +413,14 @@ async function listProjects(args = {}) {
388
413
  return api(`/api/agent/v1/projects${suffix ? `?${suffix}` : ""}`);
389
414
  }
390
415
 
416
+ async function getScorecards(args = {}) {
417
+ const projectId = await resolveProjectId(args);
418
+ if (!projectId) {
419
+ throw new Error("projectId is required. Pass projectId, set LAUNCHCHAIR_PROJECT_ID, or pass projectName.");
420
+ }
421
+ return api(`/api/agent/v1/projects/${encodeURIComponent(projectId)}/scorecards`);
422
+ }
423
+
391
424
  function normalizeProjectName(value) {
392
425
  return String(value ?? "")
393
426
  .trim()
@@ -724,6 +757,22 @@ const MCP_TOOLS = [
724
757
  additionalProperties: false,
725
758
  },
726
759
  },
760
+ {
761
+ name: "launchchair_get_scorecards",
762
+ description:
763
+ "Read the Product or Feature validation scorecards for a project, including recommended thresholds and direction-option scores kept separate. Use this whenever the user asks about validation scores or wants to compare/rerun ideas until the scorecards are strong.",
764
+ inputSchema: {
765
+ type: "object",
766
+ properties: {
767
+ projectId: { type: "string" },
768
+ projectName: {
769
+ type: "string",
770
+ description: "Optional project name to resolve through launchchair_list_projects when projectId is omitted.",
771
+ },
772
+ },
773
+ additionalProperties: false,
774
+ },
775
+ },
727
776
  {
728
777
  name: "launchchair_heartbeat",
729
778
  description: "Send heartbeat and update connected agent metadata.",
@@ -893,7 +942,7 @@ const MCP_TOOLS = [
893
942
  },
894
943
  ];
895
944
 
896
- const READ_ONLY_TOOLS = new Set(["launchchair_status", "launchchair_list_projects"]);
945
+ const READ_ONLY_TOOLS = new Set(["launchchair_status", "launchchair_list_projects", "launchchair_get_scorecards"]);
897
946
 
898
947
  function annotateTool(tool) {
899
948
  return {
@@ -1012,6 +1061,11 @@ async function handleRpc(request) {
1012
1061
  writeResult(id, textResult(payload));
1013
1062
  return;
1014
1063
  }
1064
+ if (toolName === "launchchair_get_scorecards") {
1065
+ const payload = await getScorecards(args);
1066
+ writeResult(id, textResult(payload));
1067
+ return;
1068
+ }
1015
1069
  if (toolName === "launchchair_heartbeat") {
1016
1070
  const payload = await heartbeat(args);
1017
1071
  writeResult(id, textResult(payload));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchchair/agent",
3
- "version": "0.4.2",
3
+ "version": "0.4.5",
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": {