foundry-design-web-adapter 0.2.0-beta.3 → 0.2.0-beta.4

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
@@ -4,27 +4,51 @@ Foundry is a local-first precision design workbench for Codex, Cursor, and Claud
4
4
 
5
5
  ## Beta installation
6
6
 
7
- Foundry is distributed through npm, so testers do not need access to the private GitHub repository. From the project you want to inspect, run:
7
+ Foundry is distributed through npm, so testers do not need GitHub access.
8
+
9
+ ### Recommended: let your coding agent install it
10
+
11
+ Open the project in Codex, Cursor, or Claude Code and paste:
12
+
13
+ ```text
14
+ Install Foundry for this project by running npx foundry-design@beta setup --yes. Check the result and tell me when I need to restart.
15
+ ```
16
+
17
+ Setup detects the project and active coding agent, installs development-only instrumentation, configures the local agent connection, validates the integration, and records everything it owns for safe updates or removal.
18
+
19
+ Restart the coding agent once, reopen the same project folder, and paste:
20
+
21
+ ```text
22
+ Start Foundry for this project and keep listening for Apply with agent requests.
23
+ ```
24
+
25
+ That is the normal workflow. Foundry starts the project when needed, opens an authenticated local preview, and shows **Agent is ready** before it allows an apply request.
26
+
27
+ ### Manual installation
28
+
29
+ From the project you want to inspect, run:
8
30
 
9
31
  ```bash
10
32
  npx foundry-design@beta setup
11
33
  ```
12
34
 
13
- Setup detects the platform, framework, package manager, development command, and installed coding agents. It previews every file it will manage, adds development-only instrumentation for supported web frameworks, installs the Foundry skill for Codex, Cursor, or Claude Code, configures the selected MCP clients, and records a reversible install manifest.
14
-
15
- Restart the coding agent after setup, then ask:
35
+ Then restart the coding agent, reopen the same project folder, and ask:
16
36
 
17
37
  ```text
18
- Start Foundry for this project.
38
+ Start Foundry for this project and keep listening for Apply with agent requests.
19
39
  ```
20
40
 
21
- Then start a session with:
41
+ You do not need to run a second terminal command when the agent starts Foundry for you. For a manual-only preview, run `npx foundry-design@beta start`, but Apply with agent still requires a restarted and actively listening coding agent.
42
+
43
+ Update an existing installation with:
22
44
 
23
45
  ```bash
24
- npx foundry-design@beta start
46
+ npx foundry-design@beta update
25
47
  ```
26
48
 
27
- Foundry reuses an available project server or starts the detected development command, launches the loopback runtime, and opens an authenticated visual preview. Remove only Foundry-managed integration with:
49
+ 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.
50
+
51
+ Remove only Foundry-managed integration with:
28
52
 
29
53
  ```bash
30
54
  npx foundry-design@beta uninstall
package/dist/adapter.js CHANGED
@@ -1264,6 +1264,14 @@ var PANEL_CSS = `
1264
1264
  .review-overview .review-toolbar { position:static;z-index:auto;flex:none;padding:0;border:0;background:transparent;backdrop-filter:none; }
1265
1265
  .review-overview .review-toolbar button { height:28px;padding:0 8px;border-color:transparent;background:transparent;color:var(--fdc-muted);font-size:8px; }
1266
1266
  .review-overview .review-toolbar button:hover { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }
1267
+ .review-agent { display:grid;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:12px;margin:12px 16px 0;padding:12px;border:1px solid var(--fdc-line);border-radius:8px;background:var(--fdc-paper); }
1268
+ .review-agent>i { width:8px;height:8px;border-radius:50%;background:#d16d51; }
1269
+ .review-agent.connected>i { background:#2ca67f;box-shadow:0 0 0 4px rgb(44 166 127 / 12%); }
1270
+ .review-agent strong,.review-agent span { display:block; }
1271
+ .review-agent strong { font-size:12px;font-weight:600; }
1272
+ .review-agent span { margin-top:4px;color:var(--fdc-muted);font-size:12px;line-height:1.45; }
1273
+ .review-agent button { height:32px;padding:0 12px;border:1px solid var(--fdc-line);border-radius:8px;background:var(--fdc-elevated);color:var(--fdc-ink);font-size:12px;cursor:pointer; }
1274
+ .review-agent button:hover { border-color:var(--fdc-muted); }
1267
1275
  .change-tray .review-group { border-right:0;border-bottom:1px solid var(--fdc-line); }
1268
1276
  .change-tray .review-group-title { position:sticky;top:52px;z-index:2;min-height:40px;padding:0 12px;background:rgb(28 28 31 / 98%); }
1269
1277
  .review-group-title .included-count { font-size:8px; }
@@ -2081,6 +2089,7 @@ function installFoundryInspector(options = {}) {
2081
2089
  let selectedControls = [];
2082
2090
  let resizeObserver;
2083
2091
  let activeReviewPayload = null;
2092
+ let activeAgentPresence = { connected: false, presence: null };
2084
2093
  const reviewDraftKey = `__foundry_review_draft:${sessionId || "local"}`;
2085
2094
  let reviewDraft = (() => {
2086
2095
  try {
@@ -3394,8 +3403,29 @@ function installFoundryInspector(options = {}) {
3394
3403
  const count = group.querySelector(".included-count");
3395
3404
  if (count) count.textContent = `${included} included`;
3396
3405
  });
3397
- applyButton.textContent = selectedCount ? `Apply ${selectedCount} with agent` : "Apply with agent";
3398
- applyButton.disabled = selectedCount === 0;
3406
+ applyButton.textContent = !activeAgentPresence.connected ? "Connect agent to apply" : selectedCount ? `Apply ${selectedCount} with agent` : "Apply with agent";
3407
+ applyButton.disabled = selectedCount === 0 || !activeAgentPresence.connected;
3408
+ }
3409
+ function agentConnectionMarkup() {
3410
+ const agentName = activeAgentPresence.presence?.agent?.name;
3411
+ return `<div class="review-agent ${activeAgentPresence.connected ? "connected" : "disconnected"}" aria-live="polite"><i></i><div><strong>${activeAgentPresence.connected ? `${escapeHtml(agentName ?? "Coding agent")} is ready` : "Connect your coding agent"}</strong><span>${activeAgentPresence.connected ? "Apply requests will be claimed automatically while this agent keeps listening." : "In the same project, ask your agent to start Foundry and keep listening for Apply requests."}</span></div>${activeAgentPresence.connected ? "" : "<button data-copy-agent-listener>Copy instruction</button>"}</div>`;
3412
+ }
3413
+ function updateAgentConnection() {
3414
+ const current = reviewBody.querySelector(".review-agent");
3415
+ if (!current) {
3416
+ updateReviewSelection();
3417
+ return;
3418
+ }
3419
+ const replacement = document.createElement("div");
3420
+ replacement.innerHTML = agentConnectionMarkup();
3421
+ current.replaceWith(replacement.firstElementChild);
3422
+ reviewBody.querySelector("[data-copy-agent-listener]")?.addEventListener("click", () => {
3423
+ void navigator.clipboard.writeText(
3424
+ "Start Foundry for this project and keep listening for Apply with agent requests."
3425
+ );
3426
+ showToast("Agent instruction copied");
3427
+ });
3428
+ updateReviewSelection();
3399
3429
  }
3400
3430
  function renderReviewList(changes) {
3401
3431
  const groups = /* @__PURE__ */ new Map();
@@ -3409,7 +3439,7 @@ function installFoundryInspector(options = {}) {
3409
3439
  const unresolvedCount = changes.filter(
3410
3440
  (change) => change.confidence === "unresolved" || change.mappingCandidates?.length > 1 && !change.selectedMappingId
3411
3441
  ).length;
3412
- reviewBody.innerHTML = changes.length || rejectedCount ? `<div class="review-overview"><div class="review-summary" data-unresolved="${unresolvedCount}" aria-live="polite"><strong>Preparing review\u2026</strong><span>Only included, exactly mapped changes will be sent to your agent.</span></div><div class="review-toolbar"><button data-review-compare>Compare</button><button data-review-approve-exact>Include all</button><button data-review-toggle-rejected>${reviewShowRejected ? "Hide removed" : rejectedCount ? `${rejectedCount} removed` : "Removed"}</button></div></div>${[
3442
+ reviewBody.innerHTML = changes.length || rejectedCount ? `<div class="review-overview"><div class="review-summary" data-unresolved="${unresolvedCount}" aria-live="polite"><strong>Preparing review\u2026</strong><span>Only included, exactly mapped changes will be sent to your agent.</span></div><div class="review-toolbar"><button data-review-compare>Compare</button><button data-review-approve-exact>Include all</button><button data-review-toggle-rejected>${reviewShowRejected ? "Hide removed" : rejectedCount ? `${rejectedCount} removed` : "Removed"}</button></div></div>${agentConnectionMarkup()}${[
3413
3443
  ...groups.values()
3414
3444
  ].map((group) => {
3415
3445
  const target = group[0].target;
@@ -3443,6 +3473,12 @@ function installFoundryInspector(options = {}) {
3443
3473
  reviewCancel.dataset.action = "back";
3444
3474
  reviewCancel.textContent = "Back";
3445
3475
  renderIcons(reviewBody);
3476
+ reviewBody.querySelector("[data-copy-agent-listener]")?.addEventListener("click", () => {
3477
+ void navigator.clipboard.writeText(
3478
+ "Start Foundry for this project and keep listening for Apply with agent requests."
3479
+ );
3480
+ showToast("Agent instruction copied");
3481
+ });
3446
3482
  reviewBody.querySelectorAll("[data-review-change]").forEach(
3447
3483
  (field) => field.addEventListener("change", () => {
3448
3484
  reviewDraft.selections[field.dataset.reviewChange] = field.checked;
@@ -3668,7 +3704,11 @@ function installFoundryInspector(options = {}) {
3668
3704
  async function refreshReview() {
3669
3705
  if (!workspaceState.reviewOpen || !sessionId || !token) return;
3670
3706
  try {
3671
- const payload = await sessionRequest();
3707
+ const [payload, presence] = await Promise.all([
3708
+ sessionRequest(),
3709
+ sessionRequest("/agent-presence")
3710
+ ]);
3711
+ activeAgentPresence = presence;
3672
3712
  const latestRun = payload.applyRuns?.at(-1);
3673
3713
  const runNeedsRefresh = latestRun && [
3674
3714
  "queued",
@@ -3681,6 +3721,7 @@ function installFoundryInspector(options = {}) {
3681
3721
  ].includes(latestRun.state);
3682
3722
  if (applyButton.dataset.action === "apply" && !runNeedsRefresh) {
3683
3723
  activeReviewPayload = payload;
3724
+ updateAgentConnection();
3684
3725
  return;
3685
3726
  }
3686
3727
  renderReviewPayload(payload);
@@ -3702,7 +3743,12 @@ function installFoundryInspector(options = {}) {
3702
3743
  workspaceState = updateWorkspace(workspaceState, { type: "set-review", open: true });
3703
3744
  reviewTakeover.hidden = false;
3704
3745
  outline.hidden = true;
3705
- renderReviewPayload(await sessionRequest());
3746
+ const [payload, presence] = await Promise.all([
3747
+ sessionRequest(),
3748
+ sessionRequest("/agent-presence")
3749
+ ]);
3750
+ activeAgentPresence = presence;
3751
+ renderReviewPayload(payload);
3706
3752
  requestAnimationFrame(() => {
3707
3753
  reviewBody.scrollTop = reviewScrollTop;
3708
3754
  shadow.querySelector(".review-back")?.focus();
@@ -3743,6 +3789,12 @@ function installFoundryInspector(options = {}) {
3743
3789
  );
3744
3790
  applyButton.disabled = true;
3745
3791
  try {
3792
+ activeAgentPresence = await sessionRequest("/agent-presence");
3793
+ if (!activeAgentPresence.connected) {
3794
+ updateAgentConnection();
3795
+ showToast("No coding agent is listening yet");
3796
+ return;
3797
+ }
3746
3798
  const payload = await sessionRequest("/apply-runs", {
3747
3799
  method: "POST",
3748
3800
  body: JSON.stringify({
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6DA,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;AA6+BD,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,uBAA4B,GACpC,0BAA0B,CAqvK5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6DA,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;AAq/BD,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,uBAA4B,GACpC,0BAA0B,CA4yK5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foundry-design-web-adapter",
3
- "version": "0.2.0-beta.3",
3
+ "version": "0.2.0-beta.4",
4
4
  "description": "Development-only browser inspector for Foundry",
5
5
  "type": "module",
6
6
  "main": "dist/adapter.js",