@launchchair/agent 0.5.0 → 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 CHANGED
@@ -36,6 +36,8 @@ curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/local-bridge.mjs" -o
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
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"
39
41
  curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/project-workspace.mjs" -o "$HOME/launchchair-agent/project-workspace.mjs"
40
42
  curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/runner-command.mjs" -o "$HOME/launchchair-agent/runner-command.mjs"
41
43
  curl -fsSL "https://www.launchchair.io/api/agent/v1/bridge/codex-runner.mjs" -o "$HOME/launchchair-agent/codex-runner.mjs"
@@ -131,6 +133,7 @@ Prefer `launchchair setup codex` so the CLI writes native config and verifies MC
131
133
  6. Use `launchchair_run_once` or `executionMode=local_runner` only when the user explicitly requests a separate local runner.
132
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.
133
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.
134
137
 
135
138
  ## Consent Behavior
136
139
 
package/README.md CHANGED
@@ -12,12 +12,30 @@ launchchair --version
12
12
  launchchair doctor
13
13
  ```
14
14
 
15
- Version 0.5.0 includes 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.
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.
16
16
 
17
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
18
 
19
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
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.
38
+
21
39
  ## Login
22
40
 
23
41
  Approve the CLI once in your browser. LaunchChair creates a scoped Agent API token after approval and the CLI stores it locally:
@@ -20,7 +20,7 @@ import {
20
20
  unbindProjectWorkspace,
21
21
  } from "./project-workspace.mjs";
22
22
 
23
- const VERSION = "0.5.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()
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.5.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()
@@ -20,9 +20,11 @@ import { fileURLToPath } from "node:url";
20
20
  import { resolveProjectWorkspace } from "./project-workspace.mjs";
21
21
  import { buildRunnerCommand, parseRunnerCommand } from "./runner-command.mjs";
22
22
  import { createMcpCapabilities, EXTRA_MCP_TOOLS, MCP_WORKFLOW_INSTRUCTIONS, VALIDATION_GATE_SCHEMA } from "./mcp-capabilities.mjs";
23
+ import { MCP_WIDGET_TOOLS, MCP_WIDGET_INSTRUCTIONS, listWidgetResources, readWidgetResource, callWidgetTool } from "./mcp-widgets.mjs";
23
24
 
24
- const VERSION = "0.5.0";
25
+ const VERSION = "0.5.1";
25
26
  const SERVER_NAME = "launchchair-agent-mcp";
27
+ const SUPPORTED_PROTOCOL_VERSIONS = new Set(["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"]);
26
28
  const AGENT_SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
27
29
  const CONFIG_DIR = process.env.LAUNCHCHAIR_CONFIG_DIR?.trim()
28
30
  ? path.resolve(process.env.LAUNCHCHAIR_CONFIG_DIR.trim())
@@ -181,7 +183,7 @@ function loadStatus() {
181
183
 
182
184
  function serverInstructions(status) {
183
185
  const featureInstructions = String(status?.capabilities?.mcpServerInstructions ?? "").trim();
184
- return `${BASE_SERVER_INSTRUCTIONS} ${featureInstructions} ${MCP_WORKFLOW_INSTRUCTIONS}`;
186
+ return `${BASE_SERVER_INSTRUCTIONS} ${featureInstructions} ${MCP_WORKFLOW_INSTRUCTIONS} ${MCP_WIDGET_INSTRUCTIONS}`;
185
187
  }
186
188
 
187
189
  function targetForRun(run) {
@@ -989,6 +991,7 @@ const READ_ONLY_TOOLS = new Set(["launchchair_status", "launchchair_list_project
989
991
  function annotateTool(tool) {
990
992
  return {
991
993
  ...tool,
994
+ ...(tool.name === "launchchair_select_choice" ? { _meta: { ...tool._meta, ui: { visibility: ["model", "app"] }, "openai/widgetAccessible": true } } : {}),
992
995
  annotations: {
993
996
  ...(tool.annotations ?? {}),
994
997
  readOnlyHint: tool.annotations?.readOnlyHint ?? READ_ONLY_TOOLS.has(tool.name),
@@ -1034,6 +1037,7 @@ function writeError(id, code, message, data = undefined) {
1034
1037
 
1035
1038
  function textResult(payload) {
1036
1039
  return {
1040
+ ...(payload && typeof payload === "object" && !Array.isArray(payload) ? { structuredContent: payload } : {}),
1037
1041
  content: [
1038
1042
  {
1039
1043
  type: "text",
@@ -1054,9 +1058,10 @@ async function handleRpc(request) {
1054
1058
  if (method === "initialize") {
1055
1059
  const status = await loadStatus();
1056
1060
  writeResult(id, {
1057
- protocolVersion: "2024-11-05",
1061
+ protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.has(request?.params?.protocolVersion) ? request.params.protocolVersion : "2025-11-25",
1058
1062
  capabilities: {
1059
1063
  tools: { listChanged: true },
1064
+ resources: {},
1060
1065
  },
1061
1066
  serverInfo: {
1062
1067
  name: SERVER_NAME,
@@ -1072,12 +1077,28 @@ async function handleRpc(request) {
1072
1077
  return;
1073
1078
  }
1074
1079
 
1080
+ if (method === "resources/list") {
1081
+ writeResult(id, { resources: listWidgetResources() });
1082
+ return;
1083
+ }
1084
+
1085
+ if (method === "resources/read") {
1086
+ try { writeResult(id, readWidgetResource(request?.params?.uri)); }
1087
+ catch (error) { writeError(id, -32002, error.message); }
1088
+ return;
1089
+ }
1090
+
1091
+ if (method === "ping") {
1092
+ writeResult(id, {});
1093
+ return;
1094
+ }
1095
+
1075
1096
  if (method === "tools/list") {
1076
1097
  const status = await loadStatus();
1077
1098
  const overrides = Array.isArray(status?.capabilities?.mcpToolOverrides)
1078
1099
  ? status.capabilities.mcpToolOverrides
1079
1100
  : [];
1080
- const tools = mergeToolOverrides([...MCP_TOOLS, ...EXTRA_MCP_TOOLS], overrides);
1101
+ const tools = [...mergeToolOverrides([...MCP_TOOLS, ...EXTRA_MCP_TOOLS], overrides), ...MCP_WIDGET_TOOLS];
1081
1102
  writeResult(id, { tools });
1082
1103
  return;
1083
1104
  }
@@ -1087,6 +1108,10 @@ async function handleRpc(request) {
1087
1108
  const toolName = String(params.name ?? "");
1088
1109
  const args = typeof params.arguments === "object" && params.arguments ? params.arguments : {};
1089
1110
  try {
1111
+ if (MCP_WIDGET_TOOLS.some((tool) => tool.name === toolName)) {
1112
+ writeResult(id, await callWidgetTool(toolName, args, { api, resolveProjectId, baseUrl: config.baseUrl }));
1113
+ return;
1114
+ }
1090
1115
  if (EXTRA_MCP_TOOLS.some((tool) => tool.name === toolName)) {
1091
1116
  writeResult(id, textResult(await capabilities.dispatch(toolName, args)));
1092
1117
  return;