foundry-design-web-adapter 0.2.0-beta.6 → 0.2.0-beta.7
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 +3 -1
- package/dist/adapter.js +43 -25
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ 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.
|
|
9
|
+
> **Current public beta:** `0.2.0-beta.7`. Install Foundry with the `@beta` tag. The unqualified npm `latest` tag still points to an earlier beta and is not the current testing channel.
|
|
10
10
|
|
|
11
11
|
Full documentation is available at [withfoundry.ai](https://withfoundry.ai).
|
|
12
12
|
|
|
@@ -96,7 +96,9 @@ Foundry remains local-first. Installing the plugin does not create an account, e
|
|
|
96
96
|
- Persistent, coalescing change ledger with JSON and consolidated prompt export
|
|
97
97
|
- Compact in-preview review with editable approved batches and unresolved-target blocking
|
|
98
98
|
- Persistent Apply with agent runs across Codex, Cursor, and Claude Code through MCP
|
|
99
|
+
- Leased agent handoffs that safely return abandoned or interrupted claims to the queue
|
|
99
100
|
- Live source, rebuild, validation, retry, and rendered-verification progress
|
|
101
|
+
- Rendered verification that resumes after refresh and does not depend on Review remaining open
|
|
100
102
|
- Local MCP bridge for agent access
|
|
101
103
|
- Debug adapters for web, SwiftUI, and React Native on iOS Simulator
|
|
102
104
|
- Verification records that compare requested and rendered values
|
package/dist/adapter.js
CHANGED
|
@@ -1399,6 +1399,7 @@ var PANEL_CSS = `
|
|
|
1399
1399
|
.property-control input,.property-control select,.compact-control input,.compact-control select { height:36px;font-size:12px;font-weight:400; }
|
|
1400
1400
|
.control-field .unit-select { width:44px;padding-right:24px!important;background-position:right 8px center!important; }
|
|
1401
1401
|
.section-grid { gap:8px;padding:0 16px 16px; }
|
|
1402
|
+
.inspector-category[data-category="position"]>.category-body>.property-section>.section-grid { padding-top:12px; }
|
|
1402
1403
|
@media (max-width:680px){.panel,.layers-panel{width:auto}.panel-resizer{display:none}.change-tray{right:8px;bottom:8px;left:auto;width:calc(100vw - 16px)}.review-takeover{padding:8px}.review-modal{width:calc(100vw - 16px);height:calc(100vh - 16px);border-radius:12px}.review-modal .review-actions{grid-template-columns:84px 1fr}.panel.change-summary-visible .inspector-scroll{padding-bottom:60px}}
|
|
1403
1404
|
@media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important}.layer-row.entering,.layer-branch{animation:none!important}}
|
|
1404
1405
|
`;
|
|
@@ -2122,6 +2123,7 @@ function installFoundryInspector(options = {}) {
|
|
|
2122
2123
|
let reviewShowRejected = false;
|
|
2123
2124
|
const collapsedReviewGroups = /* @__PURE__ */ new Set();
|
|
2124
2125
|
let reviewPoll;
|
|
2126
|
+
let sessionPoll;
|
|
2125
2127
|
let lastReviewTrigger = null;
|
|
2126
2128
|
let reviewScrollTop = 0;
|
|
2127
2129
|
let reviewSuspended = false;
|
|
@@ -2514,7 +2516,8 @@ function installFoundryInspector(options = {}) {
|
|
|
2514
2516
|
(change) => change.status !== "rejected" && String(change.before) !== String(change.after)
|
|
2515
2517
|
);
|
|
2516
2518
|
recordedChangeCount = activeChanges.length;
|
|
2517
|
-
|
|
2519
|
+
const latestRun = payload.applyRuns?.at(-1);
|
|
2520
|
+
latestApplyState = latestRun?.state ?? "none";
|
|
2518
2521
|
updateChangeCount(activeChanges.length, activeChanges.at(-1));
|
|
2519
2522
|
completeOnboardingStep("setup");
|
|
2520
2523
|
if (activeAgentPresence.connected) completeOnboardingStep("agent");
|
|
@@ -2524,6 +2527,7 @@ function installFoundryInspector(options = {}) {
|
|
|
2524
2527
|
renderOnboardingChecklist();
|
|
2525
2528
|
setSessionStatus("live");
|
|
2526
2529
|
if (!libraryPanel.hidden) renderDesignMemory();
|
|
2530
|
+
if (latestRun?.state === "verifying") maybeVerifyRun(latestRun);
|
|
2527
2531
|
if (changeSet.changes.length === 0 && !hydratedOnce) {
|
|
2528
2532
|
showToast("Click any element. Shift-click builds a selection.");
|
|
2529
2533
|
}
|
|
@@ -2537,7 +2541,11 @@ function installFoundryInspector(options = {}) {
|
|
|
2537
2541
|
}
|
|
2538
2542
|
}
|
|
2539
2543
|
void hydrateSession();
|
|
2540
|
-
|
|
2544
|
+
function startSessionPolling() {
|
|
2545
|
+
clearInterval(sessionPoll);
|
|
2546
|
+
sessionPoll = setInterval(() => void hydrateSession(), 5e3);
|
|
2547
|
+
}
|
|
2548
|
+
startSessionPolling();
|
|
2541
2549
|
function showToast(message) {
|
|
2542
2550
|
const toast = shadow.querySelector(".toast");
|
|
2543
2551
|
toast.textContent = message;
|
|
@@ -3520,6 +3528,12 @@ function installFoundryInspector(options = {}) {
|
|
|
3520
3528
|
const agentName = activeAgentPresence.presence?.agent?.name;
|
|
3521
3529
|
return `<div class="review-agent ${activeAgentPresence.connected ? "connected" : "disconnected"}" aria-live="polite"><i></i><div><strong>${activeAgentPresence.connected ? `${escapeHtml(agentName ?? "Coding agent")} is ready` : "Agent currently offline"}</strong><span>${activeAgentPresence.connected ? "Apply requests will be claimed automatically while this agent keeps listening." : "You can queue this batch now. Codex, Cursor, or Claude Code will claim it when the Foundry listener reconnects."}</span></div>${activeAgentPresence.connected ? "" : "<button data-copy-agent-listener>Copy reconnect instruction</button>"}</div>`;
|
|
3522
3530
|
}
|
|
3531
|
+
function copyAgentListenerInstruction() {
|
|
3532
|
+
void navigator.clipboard.writeText(
|
|
3533
|
+
"Start Foundry for this project and keep listening for Apply with agent requests."
|
|
3534
|
+
);
|
|
3535
|
+
showToast("Agent instruction copied");
|
|
3536
|
+
}
|
|
3523
3537
|
function updateAgentConnection() {
|
|
3524
3538
|
const current = reviewBody.querySelector(".review-agent");
|
|
3525
3539
|
if (!current) {
|
|
@@ -3529,12 +3543,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3529
3543
|
const replacement = document.createElement("div");
|
|
3530
3544
|
replacement.innerHTML = agentConnectionMarkup();
|
|
3531
3545
|
current.replaceWith(replacement.firstElementChild);
|
|
3532
|
-
reviewBody.querySelector("[data-copy-agent-listener]")?.addEventListener("click",
|
|
3533
|
-
void navigator.clipboard.writeText(
|
|
3534
|
-
"Start Foundry for this project and keep listening for Apply with agent requests."
|
|
3535
|
-
);
|
|
3536
|
-
showToast("Agent instruction copied");
|
|
3537
|
-
});
|
|
3546
|
+
reviewBody.querySelector("[data-copy-agent-listener]")?.addEventListener("click", copyAgentListenerInstruction);
|
|
3538
3547
|
updateReviewSelection();
|
|
3539
3548
|
}
|
|
3540
3549
|
function renderReviewList(changes) {
|
|
@@ -3700,7 +3709,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3700
3709
|
}
|
|
3701
3710
|
const runStateLabels = {
|
|
3702
3711
|
queued: "Queued for agent",
|
|
3703
|
-
claimed: "
|
|
3712
|
+
claimed: "Handoff received",
|
|
3704
3713
|
applying: "Applying source changes",
|
|
3705
3714
|
rebuilding: "Rebuilding and checking",
|
|
3706
3715
|
verifying: "Verifying rendered values",
|
|
@@ -3709,6 +3718,19 @@ function installFoundryInspector(options = {}) {
|
|
|
3709
3718
|
failed: "Apply failed",
|
|
3710
3719
|
cancelled: "Apply cancelled"
|
|
3711
3720
|
};
|
|
3721
|
+
function maybeVerifyRun(run) {
|
|
3722
|
+
if (run.state !== "verifying" || verifyingRuns.has(run.id)) return;
|
|
3723
|
+
const reloadKey = "__foundry_verifying_run";
|
|
3724
|
+
if (sessionStorage.getItem(reloadKey) !== run.id) {
|
|
3725
|
+
sessionStorage.setItem(reloadKey, run.id);
|
|
3726
|
+
location.reload();
|
|
3727
|
+
return;
|
|
3728
|
+
}
|
|
3729
|
+
verifyingRuns.add(run.id);
|
|
3730
|
+
void verify(run.changeIds, run.id).then(() => sessionStorage.removeItem(reloadKey)).catch((error) => {
|
|
3731
|
+
showToast(error instanceof Error ? error.message : "Rendered verification was interrupted");
|
|
3732
|
+
}).finally(() => verifyingRuns.delete(run.id));
|
|
3733
|
+
}
|
|
3712
3734
|
function captureVerifiedRun(run) {
|
|
3713
3735
|
if (run.state !== "passed" || capturedBaselineRuns.has(run.id)) return;
|
|
3714
3736
|
const changes = (activeReviewPayload?.changeSet?.changes ?? []).filter(
|
|
@@ -3748,13 +3770,13 @@ function installFoundryInspector(options = {}) {
|
|
|
3748
3770
|
const attention = ["needs_attention", "failed"].includes(run.state);
|
|
3749
3771
|
const passed = run.state === "passed";
|
|
3750
3772
|
const active = ["queued", "claimed", "applying", "rebuilding", "verifying"].includes(run.state);
|
|
3751
|
-
const latestMessage = run.state === "queued" ? "The reviewed changes are queued
|
|
3773
|
+
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. Waiting for source work to begin." : "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.";
|
|
3752
3774
|
latestApplyState = run.state;
|
|
3753
3775
|
if (run.state === "passed") completeOnboardingStep("apply");
|
|
3754
3776
|
captureVerifiedRun(run);
|
|
3755
3777
|
reviewCount.textContent = `Attempt ${run.attempts}`;
|
|
3756
3778
|
reviewBody.innerHTML = `<div class="run-summary"><div class="run-state"><i class="${passed ? "passed" : attention ? "attention" : active ? "active" : ""}"></i><strong>${escapeHtml(runStateLabels[run.state] ?? run.state)}</strong></div><p>${escapeHtml(latestMessage)}</p></div><div class="run-steps">${run.messages.map(
|
|
3757
|
-
(message, index) => `<div class="run-step"><span>${String(index + 1).padStart(2, "0")}</span><div><strong>${escapeHtml(runStateLabels[message.state] ?? message.state)}</strong><p>${escapeHtml(message.
|
|
3779
|
+
(message, index) => `<div class="run-step"><span>${String(index + 1).padStart(2, "0")}</span><div><strong>${escapeHtml(runStateLabels[message.state] ?? message.state)}</strong><p>${escapeHtml(message.message)}</p></div></div>`
|
|
3758
3780
|
).join(
|
|
3759
3781
|
""
|
|
3760
3782
|
)}</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(reviewValue(result.requested))} \u2192 ${escapeHtml(reviewValue(result.rendered))}</span></div>`).join("")}</div>` : ""}`;
|
|
@@ -3762,6 +3784,10 @@ function installFoundryInspector(options = {}) {
|
|
|
3762
3784
|
applyButton.dataset.action = "retry";
|
|
3763
3785
|
applyButton.textContent = "Retry with agent";
|
|
3764
3786
|
applyButton.disabled = false;
|
|
3787
|
+
} else if (["queued", "claimed"].includes(run.state) && !activeAgentPresence.connected) {
|
|
3788
|
+
applyButton.dataset.action = "reconnect";
|
|
3789
|
+
applyButton.textContent = "Reconnect agent";
|
|
3790
|
+
applyButton.disabled = false;
|
|
3765
3791
|
} else {
|
|
3766
3792
|
applyButton.dataset.action = "status";
|
|
3767
3793
|
applyButton.textContent = passed ? "Verified" : active ? runStateLabels[run.state] ?? run.state : "Run complete";
|
|
@@ -3769,19 +3795,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3769
3795
|
}
|
|
3770
3796
|
reviewCancel.dataset.action = active ? "cancel" : "back";
|
|
3771
3797
|
reviewCancel.textContent = active ? "Cancel" : "Back";
|
|
3772
|
-
|
|
3773
|
-
const reloadKey = "__foundry_verifying_run";
|
|
3774
|
-
if (sessionStorage.getItem(reloadKey) !== run.id) {
|
|
3775
|
-
sessionStorage.setItem(reloadKey, run.id);
|
|
3776
|
-
location.reload();
|
|
3777
|
-
return;
|
|
3778
|
-
}
|
|
3779
|
-
verifyingRuns.add(run.id);
|
|
3780
|
-
void verify(run.changeIds, run.id).finally(() => {
|
|
3781
|
-
verifyingRuns.delete(run.id);
|
|
3782
|
-
sessionStorage.removeItem(reloadKey);
|
|
3783
|
-
});
|
|
3784
|
-
}
|
|
3798
|
+
maybeVerifyRun(run);
|
|
3785
3799
|
}
|
|
3786
3800
|
function renderReviewPayload(payload) {
|
|
3787
3801
|
const preservedScrollTop = reviewBody.scrollTop || reviewScrollTop;
|
|
@@ -3868,7 +3882,8 @@ function installFoundryInspector(options = {}) {
|
|
|
3868
3882
|
shadow.querySelector(".review-back")?.focus();
|
|
3869
3883
|
});
|
|
3870
3884
|
clearInterval(reviewPoll);
|
|
3871
|
-
clearInterval(
|
|
3885
|
+
clearInterval(sessionPoll);
|
|
3886
|
+
sessionPoll = void 0;
|
|
3872
3887
|
reviewPoll = setInterval(() => void refreshReview(), 1e3);
|
|
3873
3888
|
}
|
|
3874
3889
|
function closeReview(restoreFocus = true) {
|
|
@@ -3877,6 +3892,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3877
3892
|
reviewTakeover.hidden = true;
|
|
3878
3893
|
clearInterval(reviewPoll);
|
|
3879
3894
|
reviewPoll = void 0;
|
|
3895
|
+
startSessionPolling();
|
|
3880
3896
|
updateOutline();
|
|
3881
3897
|
if (restoreFocus) lastReviewTrigger?.focus();
|
|
3882
3898
|
}
|
|
@@ -6394,6 +6410,7 @@ function installFoundryInspector(options = {}) {
|
|
|
6394
6410
|
applyButton.addEventListener("click", () => {
|
|
6395
6411
|
if (applyButton.dataset.action === "apply") void submitReviewedRun();
|
|
6396
6412
|
if (applyButton.dataset.action === "retry") void retryRun();
|
|
6413
|
+
if (applyButton.dataset.action === "reconnect") copyAgentListenerInstruction();
|
|
6397
6414
|
});
|
|
6398
6415
|
function handleGlobalShortcuts(event) {
|
|
6399
6416
|
if (workspaceState.reviewOpen && event.key === "Tab") {
|
|
@@ -6505,6 +6522,7 @@ function installFoundryInspector(options = {}) {
|
|
|
6505
6522
|
systemDarkTheme.removeEventListener("change", handleSystemThemeChange);
|
|
6506
6523
|
document.removeEventListener("pointerdown", handleInterfaceThemeDismiss, true);
|
|
6507
6524
|
clearInterval(reviewPoll);
|
|
6525
|
+
clearInterval(sessionPoll);
|
|
6508
6526
|
document.removeEventListener("click", handlePointer, true);
|
|
6509
6527
|
document.removeEventListener("dblclick", handleTextEdit, true);
|
|
6510
6528
|
document.removeEventListener("pointermove", handleSelectionHover, true);
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8DA,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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8DA,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;AAw/BD,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,uBAA4B,GACpC,0BAA0B,CA++K5B"}
|