foundry-design-web-adapter 0.2.0-beta.11 → 0.2.0-beta.14

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/README.md CHANGED
@@ -6,11 +6,19 @@ Foundry is a local-first precision design workbench for Codex, Cursor, and Claud
6
6
 
7
7
  Foundry is distributed through npm, so testers do not need GitHub access.
8
8
 
9
- > **Current public beta:** `0.2.0-beta.11`. Both npm `latest` and `beta` point to the same tested release. Use the unqualified command below for normal installation.
9
+ > **Release candidate:** `0.2.0-beta.14`. The commands below are prepared for this release and must not be promoted to npm `latest` until the full installation matrix passes.
10
10
 
11
11
  Full documentation is available at [withfoundry.ai](https://withfoundry.ai).
12
12
 
13
- ### Recommended: one command
13
+ ### Recommended: install once, use in every project
14
+
15
+ Install Foundry's shared connection for Codex, Cursor, and Claude once:
16
+
17
+ ```bash
18
+ npx foundry-design install
19
+ ```
20
+
21
+ Restart the selected coding agents once. Then open any project and run:
14
22
 
15
23
  Open a terminal in the project, or ask Codex, Cursor, or Claude Code to run:
16
24
 
@@ -18,7 +26,7 @@ Open a terminal in the project, or ask Codex, Cursor, or Claude Code to run:
18
26
  npx foundry-design
19
27
  ```
20
28
 
21
- That command detects the project and active coding agent, installs or safely updates Foundry, repairs the shared agent connection, validates its integration, starts the project when needed, and opens the visual session. Before changing local configuration, Foundry prints the exact CLI and MCP bridge versions it will use. On the first installation only, restart the coding agent once so it can load the shared MCP connection. A reviewed batch can be queued before the restart and will be claimed when the agent reconnects.
29
+ That command finds the nearest real project, detects its framework, installs or safely updates only the development adapter and lightweight project connection, validates it, starts the project when needed, and opens the visual session. The agent bridge and skill remain installed once at machine level. Foundry refuses to treat a home folder as a project and prints the exact CLI and MCP bridge versions before changing configuration.
22
30
 
23
31
  After the restart, reopen the same project folder and ask:
24
32
 
@@ -30,16 +38,16 @@ That is the normal workflow. Foundry resumes the most recent session for the cur
30
38
 
31
39
  ### Manual installation
32
40
 
33
- From the first project you want to inspect, run:
41
+ Install the shared connection for selected agents:
34
42
 
35
43
  ```bash
36
- npx foundry-design setup --global
44
+ npx foundry-design install --agent codex,cursor,claude
37
45
  ```
38
46
 
39
- For later projects, keep the shared agent connection and install only the development adapter:
47
+ Connect any project with only its development adapter and local project metadata:
40
48
 
41
49
  ```bash
42
- npx foundry-design setup --agent none
50
+ npx foundry-design connect
43
51
  ```
44
52
 
45
53
  Then restart the coding agent, reopen the same project folder, and ask:
@@ -48,7 +56,23 @@ Then restart the coding agent, reopen the same project folder, and ask:
48
56
  Start Foundry for this project and keep listening for Apply with agent requests.
49
57
  ```
50
58
 
51
- You do not need to run a second terminal command when the agent starts Foundry for you. Apply requests remain queued safely when the agent is offline. After an active agent claims a batch, the MCP bridge keeps that handoff alive while the agent inspects source and begins the edit. If the agent process exits, Foundry releases the abandoned claim back to the queue instead of losing it. Run `npx foundry-design doctor --repair` if the connection or generated integration needs repair.
59
+ You do not need to run a second terminal command when the agent starts Foundry for you. Apply requests remain queued safely when the agent is offline. After an active agent claims a batch, the MCP bridge keeps that handoff alive through source edits, rebuilding, and verification. A claim abandoned before source work begins returns to the queue. If the agent disappears during source work, Foundry preserves the same run in **Needs attention** and waits for you to choose **Resume with agent**. It never guesses whether a half-finished edit is safe to repeat.
60
+
61
+ Check the complete connection at any time with:
62
+
63
+ ```bash
64
+ npx foundry-design status
65
+ ```
66
+
67
+ Foundry reports project integration, the exact MCP package version, runtime health, and the live agent listener separately. Run `npx foundry-design doctor --repair` if configuration or generated integration needs repair.
68
+
69
+ If an older project has stale or conflicting project-scoped agent configuration, run:
70
+
71
+ ```bash
72
+ npx foundry-design reset
73
+ ```
74
+
75
+ Reset migrates Foundry-owned project MCP files and skills to the shared connection, preserves customized files, and reports anything it could not replace safely.
52
76
 
53
77
  Update an existing installation with:
54
78
 
@@ -56,7 +80,13 @@ Update an existing installation with:
56
80
  npx foundry-design update
57
81
  ```
58
82
 
59
- The updater refreshes checksum-matched Foundry files, agent connections, and skill bundles. It preserves and reports files changed since setup, validates the project, and rolls back the update if Foundry introduces a TypeScript or lint failure. Restart the coding agent after updating.
83
+ The updater refreshes checksum-matched project files and the shared machine connection. It removes only Foundry-owned legacy project agent files, preserves customized files, validates the project, and rolls back if Foundry introduces a TypeScript or lint failure. Restart the coding agent only when its shared bridge version changes.
84
+
85
+ Remove a project from Foundry's recent-project list without removing its adapter:
86
+
87
+ ```bash
88
+ npx foundry-design disconnect
89
+ ```
60
90
 
61
91
  Remove only Foundry-managed integration with:
62
92
 
@@ -64,15 +94,31 @@ Remove only Foundry-managed integration with:
64
94
  npx foundry-design uninstall
65
95
  ```
66
96
 
97
+ Remove the shared machine connection separately:
98
+
99
+ ```bash
100
+ npx foundry-design uninstall --global
101
+ ```
102
+
103
+ Project-scoped MCP configuration remains available only as an explicit compatibility mode:
104
+
105
+ ```bash
106
+ npx foundry-design setup --project-agent --agent codex
107
+ ```
108
+
67
109
  Supported automatic web integration currently includes Next.js App Router, Vite, and plain HTML. Generic web, SwiftUI, and React Native projects receive explicit setup guidance when a safe automatic edit is not available.
68
110
 
69
111
  The npm setup above is the public beta installation path and includes the same portable skill and MCP connection used by the agent plugin bundle.
70
112
 
113
+ ### Claude Desktop extension
114
+
115
+ The repository also produces a validated `.mcpb` extension for Claude Desktop. It bundles the local Foundry MCP bridge and can be installed through **Settings → Extensions → Advanced → Install Extension**. This provides a host-native alternative when a Claude Desktop surface does not merge the normal user-level Claude Code MCP configuration. Project instrumentation is still installed with `npx foundry-design`.
116
+
71
117
  If an npm mirror or existing `npx` cache reports an old tag, bypass it with a temporary cache and the exact current release:
72
118
 
73
119
  ```bash
74
120
  FOUNDRY_NPX_CACHE="$(mktemp -d)"
75
- npx --yes --prefer-online --registry=https://registry.npmjs.org --cache "$FOUNDRY_NPX_CACHE" --package=foundry-design@0.2.0-beta.11 foundry-design
121
+ npx --yes --prefer-online --registry=https://registry.npmjs.org --cache "$FOUNDRY_NPX_CACHE" --package=foundry-design@0.2.0-beta.14 foundry-design
76
122
  ```
77
123
 
78
124
  The beta supports Node.js 20 or newer. Read the [local-first safety model](https://withfoundry.ai/#safety) before using it with sensitive work.
@@ -87,6 +133,10 @@ Start Foundry for this project.
87
133
 
88
134
  Foundry remains local-first. Installing the plugin does not create an account, enable telemetry, or send project data to a Foundry service.
89
135
 
136
+ ### Cursor one-click connection
137
+
138
+ [Add the Foundry MCP bridge to Cursor](https://cursor.com/link/mcp/install?name=foundry-design-control&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi0tcHJlZmVyLW9ubGluZSIsImZvdW5kcnktZGVzaWduLW1jcC1zZXJ2ZXJAMC4yLjAtYmV0YS4xNCJdfQ%3D%3D), then run `npx foundry-design` inside the project. The repository's Cursor plugin additionally bundles the Foundry skill and session-start hook for marketplace distribution.
139
+
90
140
  ## Current capabilities
91
141
 
92
142
  - A dedicated local design workspace with a live product canvas, equal Layers and Inspector docks, and a direct-overlay fallback when a product blocks framing
@@ -105,6 +155,7 @@ Foundry remains local-first. Installing the plugin does not create an account, e
105
155
  - Center-workspace review with editable approved batches, grouped targets, and unresolved-target blocking
106
156
  - Persistent Apply with agent runs across Codex, Cursor, and Claude Code through MCP
107
157
  - Automatically renewed agent handoffs that remain claimed during source inspection and safely return abandoned work to the queue
158
+ - Explicit same-run recovery when an agent disappears during source editing, rebuilding, or verification
108
159
  - Live source, rebuild, validation, retry, and rendered-verification progress
109
160
  - Rendered verification that resumes after refresh and does not depend on Review remaining open
110
161
  - Local MCP bridge for agent access
@@ -123,6 +174,8 @@ pnpm check
123
174
  pnpm release:check
124
175
  pnpm release:pack
125
176
  pnpm release:test-install
177
+ pnpm test:e2e
178
+ pnpm mcpb:build
126
179
  pnpm build
127
180
  pnpm foundry setup --project /path/to/project --agent codex --local-mcp
128
181
  pnpm foundry index --project /path/to/project --output /tmp/foundry-design-graph.json
package/dist/adapter.js CHANGED
@@ -948,6 +948,43 @@ function createSafeDiagnostics(input) {
948
948
  };
949
949
  }
950
950
 
951
+ // src/apply-run.ts
952
+ var ACTIVE_APPLY_STATES = [
953
+ "queued",
954
+ "claimed",
955
+ "applying",
956
+ "rebuilding",
957
+ "verifying"
958
+ ];
959
+ function isActiveApplyRun(run) {
960
+ return ACTIVE_APPLY_STATES.includes(run.state);
961
+ }
962
+ function applyRunAction(run, agentConnected, labels) {
963
+ if (run.state === "needs_attention" && run.interruptedState) {
964
+ return { action: "resume", label: "Resume with agent", disabled: false };
965
+ }
966
+ if (run.state === "needs_attention" || run.state === "failed") {
967
+ return { action: "retry", label: "Retry with agent", disabled: false };
968
+ }
969
+ if ((run.state === "queued" || run.state === "claimed") && !agentConnected) {
970
+ return { action: "reconnect", label: "Reconnect agent", disabled: false };
971
+ }
972
+ return {
973
+ action: "status",
974
+ label: run.state === "passed" ? "Verified" : isActiveApplyRun(run) ? labels[run.state] ?? run.state : "Run complete",
975
+ disabled: true
976
+ };
977
+ }
978
+ function applyRunMessage(run, agentConnected) {
979
+ if (run.state === "queued") {
980
+ return (run.requeueCount ?? 0) > 0 ? "The previous agent did not begin source work, so Foundry safely returned this batch to the queue." : "The reviewed changes are queued and ready for an active coding agent.";
981
+ }
982
+ if (run.state === "claimed") {
983
+ return agentConnected ? "The agent received this batch. Foundry is keeping the handoff active while source work begins." : "The agent disconnected before source work began. Foundry will return this batch to the queue shortly.";
984
+ }
985
+ return run.messages?.at(-1)?.message ?? run.error ?? "Apply run created.";
986
+ }
987
+
951
988
  // src/workspace.ts
952
989
  function resolveInterfaceTheme(preference, systemPrefersDark) {
953
990
  return preference === "system" ? systemPrefersDark ? "dark" : "light" : preference;
@@ -5388,8 +5425,8 @@ function installFoundryInspector(options = {}) {
5388
5425
  function renderApplyRun(run) {
5389
5426
  const attention = ["needs_attention", "failed"].includes(run.state);
5390
5427
  const passed = run.state === "passed";
5391
- const active = ["queued", "claimed", "applying", "rebuilding", "verifying"].includes(run.state);
5392
- const latestMessage = run.state === "queued" ? run.requeueCount > 0 ? "The previous agent did not begin source work, so Foundry safely returned this batch to the queue." : "The reviewed changes are queued and ready for an active coding agent." : run.state === "claimed" ? activeAgentPresence.connected ? "The agent received this batch. Foundry is keeping the handoff active while source work begins." : "The agent disconnected before source work began. Foundry will return this batch to the queue shortly." : run.messages.at(-1)?.message ?? run.error ?? "Apply run created.";
5428
+ const active = isActiveApplyRun(run);
5429
+ const latestMessage = applyRunMessage(run, activeAgentPresence.connected);
5393
5430
  latestApplyState = run.state;
5394
5431
  if (run.state === "passed") completeOnboardingStep("apply");
5395
5432
  captureVerifiedRun(run);
@@ -5399,19 +5436,10 @@ function installFoundryInspector(options = {}) {
5399
5436
  ).join(
5400
5437
  ""
5401
5438
  )}</div>${run.changedFiles.length ? `<div class="run-files"><strong>Changed files</strong>${run.changedFiles.map((file) => `<code>${escapeHtml(file)}</code>`).join("")}</div>` : ""}${run.validationResults.length ? `<div class="result-list">${run.validationResults.map((result) => `<div class="result-row ${result.passed ? "pass" : "fail"}"><span>${result.passed ? "Passed" : "Failed"} \xB7 ${escapeHtml(result.name)}</span><span>${escapeHtml(result.summary ?? "")}</span></div>`).join("")}</div>` : ""}${run.verificationResults.length ? `<div class="result-list">${run.verificationResults.map((result) => `<div class="result-row ${result.passed ? "pass" : "fail"}"><span>${result.passed ? "Matched" : "Mismatch"} \xB7 ${escapeHtml(result.property)}</span><span>${escapeHtml(verificationResultValue(result))}${result.reason ? `<br/>${escapeHtml(result.reason)}` : ""}</span></div>`).join("")}</div>` : ""}`;
5402
- if (attention) {
5403
- applyButton.dataset.action = "retry";
5404
- applyButton.textContent = "Retry with agent";
5405
- applyButton.disabled = false;
5406
- } else if (["queued", "claimed"].includes(run.state) && !activeAgentPresence.connected) {
5407
- applyButton.dataset.action = "reconnect";
5408
- applyButton.textContent = "Reconnect agent";
5409
- applyButton.disabled = false;
5410
- } else {
5411
- applyButton.dataset.action = "status";
5412
- applyButton.textContent = passed ? "Verified" : active ? runStateLabels[run.state] ?? run.state : "Run complete";
5413
- applyButton.disabled = true;
5414
- }
5439
+ const primaryAction = applyRunAction(run, activeAgentPresence.connected, runStateLabels);
5440
+ applyButton.dataset.action = primaryAction.action;
5441
+ applyButton.textContent = primaryAction.label;
5442
+ applyButton.disabled = primaryAction.disabled;
5415
5443
  const confirmingCancel = active && cancelConfirmationRunId === run.id && Date.now() < cancelConfirmationUntil;
5416
5444
  reviewCancel.dataset.action = active ? "cancel" : "back";
5417
5445
  reviewCancel.textContent = active ? confirmingCancel ? "Confirm stop" : "Stop apply" : "Back";
@@ -5570,6 +5598,21 @@ function installFoundryInspector(options = {}) {
5570
5598
  showToast(error instanceof Error ? error.message : "Could not retry apply run");
5571
5599
  }
5572
5600
  }
5601
+ async function resumeRun() {
5602
+ const run = activeReviewPayload?.applyRuns?.at(-1);
5603
+ if (!run) return;
5604
+ try {
5605
+ renderReviewPayload(
5606
+ await sessionRequest(`/apply-runs/${encodeURIComponent(run.id)}/resume`, {
5607
+ method: "POST",
5608
+ body: "{}"
5609
+ })
5610
+ );
5611
+ showToast("Resume authorized. Waiting for an agent to reinspect this run.");
5612
+ } catch (error) {
5613
+ showToast(error instanceof Error ? error.message : "Could not resume apply run");
5614
+ }
5615
+ }
5573
5616
  async function cancelRun() {
5574
5617
  const run = activeReviewPayload?.applyRuns?.at(-1);
5575
5618
  if (!run) return;
@@ -9206,6 +9249,7 @@ function installFoundryInspector(options = {}) {
9206
9249
  applyButton.addEventListener("click", () => {
9207
9250
  if (applyButton.dataset.action === "apply") void submitReviewedRun();
9208
9251
  if (applyButton.dataset.action === "retry") void retryRun();
9252
+ if (applyButton.dataset.action === "resume") void resumeRun();
9209
9253
  if (applyButton.dataset.action === "reconnect") copyAgentListenerInstruction();
9210
9254
  });
9211
9255
  function handleGlobalShortcuts(event) {
@@ -0,0 +1,19 @@
1
+ export interface ApplyRunView {
2
+ state: string;
3
+ interruptedState?: 'applying' | 'rebuilding' | 'verifying';
4
+ requeueCount?: number;
5
+ error?: string;
6
+ messages?: Array<{
7
+ message: string;
8
+ }>;
9
+ }
10
+ export interface ApplyRunAction {
11
+ action: 'resume' | 'retry' | 'reconnect' | 'status';
12
+ label: string;
13
+ disabled: boolean;
14
+ }
15
+ export declare const ACTIVE_APPLY_STATES: readonly ["queued", "claimed", "applying", "rebuilding", "verifying"];
16
+ export declare function isActiveApplyRun(run: ApplyRunView): boolean;
17
+ export declare function applyRunAction(run: ApplyRunView, agentConnected: boolean, labels: Record<string, string>): ApplyRunAction;
18
+ export declare function applyRunMessage(run: ApplyRunView, agentConnected: boolean): string;
19
+ //# sourceMappingURL=apply-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-run.d.ts","sourceRoot":"","sources":["../src/apply-run.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,mBAAmB,uEAMtB,CAAC;AAEX,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAE3D;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,YAAY,EACjB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,cAAc,CAoBhB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CAYlF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgHA,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,IAAI,IAAI,CAAC;IAChB,cAAc,IAAI,IAAI,CAAC;IACvB,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,OAAO,IAAI,IAAI,CAAC;CACjB;AA4lCD,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,uBAA4B,GACpC,0BAA0B,CA2jP5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiHA,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,IAAI,IAAI,CAAC;IAChB,cAAc,IAAI,IAAI,CAAC;IACvB,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,OAAO,IAAI,IAAI,CAAC;CACjB;AA4lCD,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,uBAA4B,GACpC,0BAA0B,CAsjP5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foundry-design-web-adapter",
3
- "version": "0.2.0-beta.11",
3
+ "version": "0.2.0-beta.14",
4
4
  "description": "Development-only browser inspector for Foundry",
5
5
  "type": "module",
6
6
  "main": "dist/adapter.js",