foundry-design-web-adapter 0.2.0-beta.4 → 0.2.0-beta.6
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 +23 -13
- package/dist/adapter.js +176 -18
- package/dist/diagnostics.d.ts +27 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,30 +6,40 @@ 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
|
-
|
|
9
|
+
> **Current public beta:** `0.2.0-beta.6`. 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
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
### Recommended: one command
|
|
14
|
+
|
|
15
|
+
Open a terminal in the project, or ask Codex, Cursor, or Claude Code to run:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx foundry-design@beta
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
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. 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.
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
After the restart, reopen the same project folder and ask:
|
|
20
24
|
|
|
21
25
|
```text
|
|
22
26
|
Start Foundry for this project and keep listening for Apply with agent requests.
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
That is the normal workflow. Foundry
|
|
29
|
+
That is the normal workflow. Foundry resumes the most recent session for the current source revision and keeps all review and apply state local.
|
|
26
30
|
|
|
27
31
|
### Manual installation
|
|
28
32
|
|
|
29
|
-
From the project you want to inspect, run:
|
|
33
|
+
From the first project you want to inspect, run:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx foundry-design@beta setup --global
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For later projects, keep the shared agent connection and install only the development adapter:
|
|
30
40
|
|
|
31
41
|
```bash
|
|
32
|
-
npx foundry-design@beta setup
|
|
42
|
+
npx foundry-design@beta setup --agent none
|
|
33
43
|
```
|
|
34
44
|
|
|
35
45
|
Then restart the coding agent, reopen the same project folder, and ask:
|
|
@@ -38,7 +48,7 @@ Then restart the coding agent, reopen the same project folder, and ask:
|
|
|
38
48
|
Start Foundry for this project and keep listening for Apply with agent requests.
|
|
39
49
|
```
|
|
40
50
|
|
|
41
|
-
You do not need to run a second terminal command when the agent starts Foundry for you.
|
|
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. Run `npx foundry-design@beta doctor --repair` if the connection or generated integration needs repair.
|
|
42
52
|
|
|
43
53
|
Update an existing installation with:
|
|
44
54
|
|
|
@@ -56,13 +66,13 @@ npx foundry-design@beta uninstall
|
|
|
56
66
|
|
|
57
67
|
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.
|
|
58
68
|
|
|
59
|
-
The
|
|
69
|
+
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.
|
|
60
70
|
|
|
61
|
-
The beta supports Node.js 20 or newer. Read
|
|
71
|
+
The beta supports Node.js 20 or newer. Read the [local-first safety model](https://withfoundry.ai/#safety) before using it with sensitive work.
|
|
62
72
|
|
|
63
73
|
## Agent plugin
|
|
64
74
|
|
|
65
|
-
The portable plugin lives at `plugins/foundry-design-control`. The repository also includes marketplace manifests for Codex, Cursor, and Claude-compatible plugin import. Once installed, ask your agent:
|
|
75
|
+
The portable plugin lives at `plugins/foundry-design-control`. The repository also includes marketplace manifests for Codex, Cursor, and Claude-compatible plugin import. Until public marketplace review is complete, `setup --global` installs the same reusable skill and MCP connection from npm without requiring source-repository access. Once installed, ask your agent:
|
|
66
76
|
|
|
67
77
|
```text
|
|
68
78
|
Start Foundry for this project.
|
package/dist/adapter.js
CHANGED
|
@@ -896,6 +896,25 @@ var FOUNDRY_UI_FOUNDATION_CSS = `
|
|
|
896
896
|
}
|
|
897
897
|
`;
|
|
898
898
|
|
|
899
|
+
// src/diagnostics.ts
|
|
900
|
+
function createSafeDiagnostics(input) {
|
|
901
|
+
return {
|
|
902
|
+
product: "Foundry Design Control",
|
|
903
|
+
protocolVersion: input.protocolVersion ?? "1.1.0",
|
|
904
|
+
interfaceTheme: input.interfaceTheme,
|
|
905
|
+
connection: {
|
|
906
|
+
runtime: input.runtimeConnected ? "connected" : "disconnected",
|
|
907
|
+
agent: input.agentConnected ? "connected" : "disconnected",
|
|
908
|
+
...input.agentConnected && input.agentName ? { agentName: input.agentName } : {}
|
|
909
|
+
},
|
|
910
|
+
workspace: {
|
|
911
|
+
selectedElementCount: Math.max(0, input.selectedCount),
|
|
912
|
+
recordedChangeCount: Math.max(0, input.recordedChangeCount),
|
|
913
|
+
latestApplyState: input.latestApplyState ?? "none"
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
899
918
|
// src/workspace.ts
|
|
900
919
|
function resolveInterfaceTheme(preference, systemPrefersDark) {
|
|
901
920
|
return preference === "system" ? systemPrefersDark ? "dark" : "light" : preference;
|
|
@@ -1197,6 +1216,8 @@ var PANEL_CSS = `
|
|
|
1197
1216
|
.review-head strong { font-size:12px; }.review-summary { padding:12px 16px 12px;border-bottom:1px solid var(--fdc-line);background:#fcfcfc; }.review-summary strong { display:block;font-size:12px;font-weight:550;letter-spacing:-.01em; }.review-summary span { display:block;margin-top:4px;color:var(--fdc-muted);font-size:12px;line-height:1.45; }.review-summary.attention strong { color:#8b4d3d; }.review-toolbar button { height:28px;padding:0 8px;font-size:12px; }
|
|
1198
1217
|
.onboarding-card { bottom:84px;width:340px;padding:16px;border-radius:12px;box-shadow:0 16px 40px rgb(0 0 0 / 15%); }.onboarding-card-head { gap:8px; }.onboarding-card-head span { width:28px;height:28px;display:grid;place-items:center;color:#a75031;background:#fbf1ed;border-radius:8px; }.onboarding-card-head svg { width:16px;height:16px;color:inherit; }.onboarding-card-head strong { font-size:12px;letter-spacing:-.015em; }.onboarding-card>p { margin:8px 0 16px;font-size:12px;line-height:1.55; }.onboarding-steps { display:grid;grid-template-columns:1fr;gap:1px;border:1px solid var(--fdc-line);border-radius:8px;overflow:hidden;background:var(--fdc-line); }.onboarding-step { display:grid;grid-template-columns:24px 1fr;gap:8px;padding:8px 12px;background:white;text-align:left; }.onboarding-step b { color:#8a8a8a;font-size:8px;font-weight:500;letter-spacing:.04em; }.onboarding-step strong { display:block;font-size:12px;font-weight:550; }.onboarding-step small { display:block;margin-top:4px;color:var(--fdc-muted);font-size:8px;line-height:1.35; }.onboarding-actions { gap:8px;margin-top:12px; }.onboarding-actions button { height:32px;padding:0 12px;border-radius:8px;font-size:12px; }
|
|
1199
1218
|
.onboarding-card,.onboarding-step { color:var(--fdc-ink);background:var(--fdc-surface); }.onboarding-card-head span { color:#e7a68c;background:#36231d; }.onboarding-actions button { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }.onboarding-actions .onboarding-start { color:#141416;background:#f0f1f3;border-color:#f0f1f3; }
|
|
1219
|
+
.status-popover { width:256px; }.status-popover-actions { display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-top:8px; }.status-popover .status-popover-actions button { height:32px;margin:0; }.status-popover .status-popover-actions [data-status-retry],.status-popover .status-popover-actions [data-status-repair] { grid-column:1/-1; }
|
|
1220
|
+
.onboarding-card { width:360px; }.onboarding-card-head>strong { flex:1; }.onboarding-card-head .onboarding-close { width:28px;height:28px;display:grid;place-items:center;padding:0;border:0;border-radius:4px;background:transparent;color:var(--fdc-muted);cursor:pointer; }.onboarding-card-head .onboarding-close:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }.onboarding-card-head .onboarding-close svg { width:12px;height:12px; }.onboarding-steps { gap:4px;border:0;overflow:visible;background:transparent; }.onboarding-step { min-height:40px;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:8px;padding:8px;border:1px solid var(--fdc-line);border-radius:8px; }.onboarding-step b { width:20px;height:20px;display:grid;place-items:center;border:1px solid var(--fdc-line);border-radius:50%;color:var(--fdc-muted);font:500 8px/1 var(--fdc-font);letter-spacing:0; }.onboarding-step b svg { width:12px;height:12px; }.onboarding-step.complete>b { color:#141416;background:#8ae0c2;border-color:#8ae0c2; }.onboarding-step.current { border-color:var(--fdc-signal);box-shadow:0 0 0 4px rgb(59 130 246 / 10%); }
|
|
1200
1221
|
.review-summary { color:var(--fdc-ink);background:var(--fdc-paper); }.empty-state-icon { color:#9ec5ff;background:var(--fdc-signal-soft); }
|
|
1201
1222
|
.component-card,.health-card { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line); }.component-card.selected { color:var(--fdc-ink);background:var(--fdc-component-soft);border-color:#5c4b9e;box-shadow:0 0 0 4px rgb(155 135 245 / 10%); }.component-variants span,.component-actions button,.component-variants button { color:#c1b5f5;background:var(--fdc-component-soft);border-color:#4a406f; }.health-score::before { background:var(--fdc-surface); }.health-filters button { color:var(--fdc-muted); }.health-filters button:hover,.health-filters button.active { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }.health-card p,.health-evidence { color:var(--fdc-muted); }.mapping-chooser { color:#f0c9a8;background:#35291d;border-color:#665039; }.mapping-chooser>strong,.mapping-option,.mapping-option small { color:#e7c29f; }.review-card.locating { background:var(--fdc-signal-soft); }.baseline-badge { color:#83d8bb;background:#18352c; }
|
|
1202
1223
|
/* Workspace ownership */
|
|
@@ -1891,7 +1912,7 @@ function installFoundryInspector(options = {}) {
|
|
|
1891
1912
|
statusPill.setAttribute("aria-label", "Foundry session status");
|
|
1892
1913
|
statusPill.insertAdjacentHTML(
|
|
1893
1914
|
"afterend",
|
|
1894
|
-
'<div class="status-popover" hidden><strong data-status-title>Session connected</strong><span data-status-detail>Changes are stored locally.</span><code data-status-project></code><code data-status-revision></code><button data-status-retry>Check connection</button></div>'
|
|
1915
|
+
'<div class="status-popover" hidden><strong data-status-title>Session connected</strong><span data-status-detail>Changes are stored locally.</span><code data-status-project></code><code data-status-revision></code><div class="status-popover-actions"><button data-status-checklist>Getting started</button><button data-status-diagnostics>Copy diagnostics</button><button data-status-retry>Check connection</button><button data-status-repair>Copy repair command</button></div></div>'
|
|
1895
1916
|
);
|
|
1896
1917
|
shadow.querySelector(".panel").insertAdjacentHTML(
|
|
1897
1918
|
"beforeend",
|
|
@@ -1901,7 +1922,7 @@ function installFoundryInspector(options = {}) {
|
|
|
1901
1922
|
onboarding.className = "onboarding-card";
|
|
1902
1923
|
onboarding.hidden = true;
|
|
1903
1924
|
onboarding.setAttribute("aria-label", "Getting started with Foundry");
|
|
1904
|
-
onboarding.innerHTML = '<div class="onboarding-card-head"><span><i data-foundry-icon="sparkles"></i></span><strong>
|
|
1925
|
+
onboarding.innerHTML = '<div class="onboarding-card-head"><span><i data-foundry-icon="sparkles"></i></span><strong>Getting started</strong><button class="onboarding-close" aria-label="Close getting started"><i data-foundry-icon="x"></i></button></div><p>Complete one real design loop. Progress stays in this browser and contains no project content.</p><div class="onboarding-steps"></div><div class="onboarding-actions"><button class="onboarding-shortcuts">View shortcuts</button><button class="onboarding-start">Continue</button></div>';
|
|
1905
1926
|
shadow.append(onboarding);
|
|
1906
1927
|
const compareBar = document.createElement("div");
|
|
1907
1928
|
compareBar.className = "compare-bar";
|
|
@@ -2152,10 +2173,84 @@ function installFoundryInspector(options = {}) {
|
|
|
2152
2173
|
const capturedBaselineRuns = /* @__PURE__ */ new Set();
|
|
2153
2174
|
let projectRoot = location.origin;
|
|
2154
2175
|
let projectRevision = "";
|
|
2176
|
+
let runtimeConnected = false;
|
|
2177
|
+
let recordedChangeCount = 0;
|
|
2178
|
+
let latestApplyState = "none";
|
|
2179
|
+
const onboardingCompleted = /* @__PURE__ */ new Set();
|
|
2155
2180
|
let designMemory = emptyDesignMemory();
|
|
2156
2181
|
let matrixMode = false;
|
|
2157
2182
|
let lastUtilityTrigger = null;
|
|
2158
2183
|
const utilityRects = /* @__PURE__ */ new Map();
|
|
2184
|
+
const onboardingSteps = [
|
|
2185
|
+
{
|
|
2186
|
+
id: "setup",
|
|
2187
|
+
title: "Setup complete",
|
|
2188
|
+
detail: "The project adapter and local session are ready."
|
|
2189
|
+
},
|
|
2190
|
+
{
|
|
2191
|
+
id: "agent",
|
|
2192
|
+
title: "Agent connection",
|
|
2193
|
+
detail: "Keep it listening while you design. Offline batches wait safely."
|
|
2194
|
+
},
|
|
2195
|
+
{
|
|
2196
|
+
id: "selection",
|
|
2197
|
+
title: "First element selected",
|
|
2198
|
+
detail: "Click the canvas or choose an item in Layers."
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
id: "change",
|
|
2202
|
+
title: "First change recorded",
|
|
2203
|
+
detail: "Adjust a measured value in the Inspector."
|
|
2204
|
+
},
|
|
2205
|
+
{
|
|
2206
|
+
id: "apply",
|
|
2207
|
+
title: "First batch applied and verified",
|
|
2208
|
+
detail: "Review once, update source, then measure the rebuild."
|
|
2209
|
+
}
|
|
2210
|
+
];
|
|
2211
|
+
function onboardingStorageKey(suffix) {
|
|
2212
|
+
return `__foundry_getting_started:${suffix}:${projectRoot}`;
|
|
2213
|
+
}
|
|
2214
|
+
function loadOnboardingProgress() {
|
|
2215
|
+
onboardingCompleted.clear();
|
|
2216
|
+
try {
|
|
2217
|
+
const stored = JSON.parse(localStorage.getItem(onboardingStorageKey("completed")) ?? "[]");
|
|
2218
|
+
for (const id of stored) {
|
|
2219
|
+
if (onboardingSteps.some((step) => step.id === id)) onboardingCompleted.add(id);
|
|
2220
|
+
}
|
|
2221
|
+
} catch {
|
|
2222
|
+
localStorage.removeItem(onboardingStorageKey("completed"));
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
function completeOnboardingStep(id) {
|
|
2226
|
+
if (onboardingCompleted.has(id)) return;
|
|
2227
|
+
onboardingCompleted.add(id);
|
|
2228
|
+
try {
|
|
2229
|
+
localStorage.setItem(
|
|
2230
|
+
onboardingStorageKey("completed"),
|
|
2231
|
+
JSON.stringify([...onboardingCompleted])
|
|
2232
|
+
);
|
|
2233
|
+
} catch {
|
|
2234
|
+
}
|
|
2235
|
+
renderOnboardingChecklist();
|
|
2236
|
+
}
|
|
2237
|
+
function renderOnboardingChecklist(forceOpen = false) {
|
|
2238
|
+
const nextStep = onboardingSteps.find((step) => !onboardingCompleted.has(step.id));
|
|
2239
|
+
const complete = !nextStep;
|
|
2240
|
+
const stepsRoot = onboarding.querySelector(".onboarding-steps");
|
|
2241
|
+
stepsRoot.innerHTML = onboardingSteps.map((step, index) => {
|
|
2242
|
+
const done = onboardingCompleted.has(step.id);
|
|
2243
|
+
const current = step.id === nextStep?.id;
|
|
2244
|
+
return `<div class="onboarding-step ${done ? "complete" : ""} ${current ? "current" : ""}"><b>${done ? '<i data-foundry-icon="check"></i>' : String(index + 1).padStart(2, "0")}</b><span><strong>${step.title}</strong><small>${step.detail}</small></span></div>`;
|
|
2245
|
+
}).join("");
|
|
2246
|
+
renderIcons(stepsRoot);
|
|
2247
|
+
const continueButton = onboarding.querySelector(".onboarding-start");
|
|
2248
|
+
const action = nextStep?.id ?? "done";
|
|
2249
|
+
continueButton.dataset.action = action;
|
|
2250
|
+
continueButton.textContent = action === "agent" ? "Copy restart prompt" : action === "selection" ? "Select an element" : action === "change" ? "Adjust a value" : action === "apply" ? "Review changes" : "Done";
|
|
2251
|
+
const dismissed = localStorage.getItem(onboardingStorageKey("dismissed")) === "1";
|
|
2252
|
+
onboarding.hidden = complete || !forceOpen && dismissed;
|
|
2253
|
+
}
|
|
2159
2254
|
function utilityStorageKey(utility) {
|
|
2160
2255
|
return `__foundry_utility_rect:${utility}:${projectRoot}`;
|
|
2161
2256
|
}
|
|
@@ -2389,16 +2484,23 @@ function installFoundryInspector(options = {}) {
|
|
|
2389
2484
|
async function hydrateSession() {
|
|
2390
2485
|
if (!sessionId || !token) return;
|
|
2391
2486
|
try {
|
|
2392
|
-
const response = await
|
|
2393
|
-
|
|
2394
|
-
|
|
2487
|
+
const [response, presence] = await Promise.all([
|
|
2488
|
+
fetch(`${runtimeUrl}/v1/sessions/${sessionId}`, {
|
|
2489
|
+
headers: { "x-foundry-token": token }
|
|
2490
|
+
}),
|
|
2491
|
+
sessionRequest("/agent-presence").catch(() => ({ connected: false, presence: null }))
|
|
2492
|
+
]);
|
|
2395
2493
|
if (!response.ok) throw new Error("The local session could not be read.");
|
|
2396
|
-
const
|
|
2494
|
+
const payload = await response.json();
|
|
2495
|
+
const { changeSet, designGraph: graph } = payload;
|
|
2496
|
+
runtimeConnected = true;
|
|
2497
|
+
activeAgentPresence = presence;
|
|
2397
2498
|
statusPopover.querySelector("[data-status-project]").textContent = changeSet.context.projectRoot;
|
|
2398
2499
|
statusPopover.querySelector("[data-status-revision]").textContent = `Revision ${changeSet.context.revision ?? "working tree"}`;
|
|
2399
2500
|
const nextProjectRoot = changeSet.context.projectRoot || location.origin;
|
|
2400
2501
|
if (projectRoot !== nextProjectRoot || !hydratedOnce) {
|
|
2401
2502
|
projectRoot = nextProjectRoot;
|
|
2503
|
+
loadOnboardingProgress();
|
|
2402
2504
|
designMemory = readDesignMemory(localStorage, projectRoot);
|
|
2403
2505
|
utilityRects.clear();
|
|
2404
2506
|
positionWorkspaceSurfaces();
|
|
@@ -2411,15 +2513,23 @@ function installFoundryInspector(options = {}) {
|
|
|
2411
2513
|
const activeChanges = changeSet.changes.filter(
|
|
2412
2514
|
(change) => change.status !== "rejected" && String(change.before) !== String(change.after)
|
|
2413
2515
|
);
|
|
2516
|
+
recordedChangeCount = activeChanges.length;
|
|
2517
|
+
latestApplyState = payload.applyRuns?.at(-1)?.state ?? "none";
|
|
2414
2518
|
updateChangeCount(activeChanges.length, activeChanges.at(-1));
|
|
2519
|
+
completeOnboardingStep("setup");
|
|
2520
|
+
if (activeAgentPresence.connected) completeOnboardingStep("agent");
|
|
2521
|
+
if (selectedElements.length) completeOnboardingStep("selection");
|
|
2522
|
+
if (activeChanges.length) completeOnboardingStep("change");
|
|
2523
|
+
if (latestApplyState === "passed") completeOnboardingStep("apply");
|
|
2524
|
+
renderOnboardingChecklist();
|
|
2415
2525
|
setSessionStatus("live");
|
|
2416
2526
|
if (!libraryPanel.hidden) renderDesignMemory();
|
|
2417
2527
|
if (changeSet.changes.length === 0 && !hydratedOnce) {
|
|
2418
2528
|
showToast("Click any element. Shift-click builds a selection.");
|
|
2419
|
-
if (!localStorage.getItem("__foundry_onboarded")) onboarding.hidden = false;
|
|
2420
2529
|
}
|
|
2421
2530
|
hydratedOnce = true;
|
|
2422
2531
|
} catch (error) {
|
|
2532
|
+
runtimeConnected = false;
|
|
2423
2533
|
setSessionStatus(
|
|
2424
2534
|
"error",
|
|
2425
2535
|
error instanceof Error ? error.message : "The local session could not be read."
|
|
@@ -3403,12 +3513,12 @@ function installFoundryInspector(options = {}) {
|
|
|
3403
3513
|
const count = group.querySelector(".included-count");
|
|
3404
3514
|
if (count) count.textContent = `${included} included`;
|
|
3405
3515
|
});
|
|
3406
|
-
applyButton.textContent =
|
|
3407
|
-
applyButton.disabled = selectedCount === 0
|
|
3516
|
+
applyButton.textContent = selectedCount ? activeAgentPresence.connected ? `Apply ${selectedCount} with agent` : `Queue ${selectedCount} for agent` : "Apply with agent";
|
|
3517
|
+
applyButton.disabled = selectedCount === 0;
|
|
3408
3518
|
}
|
|
3409
3519
|
function agentConnectionMarkup() {
|
|
3410
3520
|
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` : "
|
|
3521
|
+
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>`;
|
|
3412
3522
|
}
|
|
3413
3523
|
function updateAgentConnection() {
|
|
3414
3524
|
const current = reviewBody.querySelector(".review-agent");
|
|
@@ -3639,6 +3749,8 @@ function installFoundryInspector(options = {}) {
|
|
|
3639
3749
|
const passed = run.state === "passed";
|
|
3640
3750
|
const active = ["queued", "claimed", "applying", "rebuilding", "verifying"].includes(run.state);
|
|
3641
3751
|
const latestMessage = run.state === "queued" ? "The reviewed changes are queued. Keep your coding agent active, or ask it to apply your reviewed Foundry changes." : run.messages.at(-1)?.message ?? run.error ?? "Apply run created.";
|
|
3752
|
+
latestApplyState = run.state;
|
|
3753
|
+
if (run.state === "passed") completeOnboardingStep("apply");
|
|
3642
3754
|
captureVerifiedRun(run);
|
|
3643
3755
|
reviewCount.textContent = `Attempt ${run.attempts}`;
|
|
3644
3756
|
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(
|
|
@@ -3709,6 +3821,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3709
3821
|
sessionRequest("/agent-presence")
|
|
3710
3822
|
]);
|
|
3711
3823
|
activeAgentPresence = presence;
|
|
3824
|
+
if (presence.connected) completeOnboardingStep("agent");
|
|
3712
3825
|
const latestRun = payload.applyRuns?.at(-1);
|
|
3713
3826
|
const runNeedsRefresh = latestRun && [
|
|
3714
3827
|
"queued",
|
|
@@ -3748,6 +3861,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3748
3861
|
sessionRequest("/agent-presence")
|
|
3749
3862
|
]);
|
|
3750
3863
|
activeAgentPresence = presence;
|
|
3864
|
+
if (presence.connected) completeOnboardingStep("agent");
|
|
3751
3865
|
renderReviewPayload(payload);
|
|
3752
3866
|
requestAnimationFrame(() => {
|
|
3753
3867
|
reviewBody.scrollTop = reviewScrollTop;
|
|
@@ -3790,11 +3904,6 @@ function installFoundryInspector(options = {}) {
|
|
|
3790
3904
|
applyButton.disabled = true;
|
|
3791
3905
|
try {
|
|
3792
3906
|
activeAgentPresence = await sessionRequest("/agent-presence");
|
|
3793
|
-
if (!activeAgentPresence.connected) {
|
|
3794
|
-
updateAgentConnection();
|
|
3795
|
-
showToast("No coding agent is listening yet");
|
|
3796
|
-
return;
|
|
3797
|
-
}
|
|
3798
3907
|
const payload = await sessionRequest("/apply-runs", {
|
|
3799
3908
|
method: "POST",
|
|
3800
3909
|
body: JSON.stringify({
|
|
@@ -3804,6 +3913,8 @@ function installFoundryInspector(options = {}) {
|
|
|
3804
3913
|
});
|
|
3805
3914
|
clearReviewDraft();
|
|
3806
3915
|
renderReviewPayload(payload);
|
|
3916
|
+
if (!activeAgentPresence.connected)
|
|
3917
|
+
showToast("Queued. Your coding agent will claim this batch when it reconnects.");
|
|
3807
3918
|
} catch (error) {
|
|
3808
3919
|
showToast(error instanceof Error ? error.message : "Could not start apply run");
|
|
3809
3920
|
updateReviewSelection();
|
|
@@ -4049,6 +4160,8 @@ function installFoundryInspector(options = {}) {
|
|
|
4049
4160
|
const activeChanges = responsePayload.changeSet.changes.filter(
|
|
4050
4161
|
(change) => change.status !== "rejected" && String(change.before) !== String(change.after)
|
|
4051
4162
|
);
|
|
4163
|
+
recordedChangeCount = activeChanges.length;
|
|
4164
|
+
completeOnboardingStep("change");
|
|
4052
4165
|
lastRecordedSummary = `${target.label} \xB7 ${control.label} ${before}${control.unit ?? ""} \u2192 ${after}${control.unit ?? ""}`;
|
|
4053
4166
|
updateChangeCount(activeChanges.length, activeChanges.at(-1));
|
|
4054
4167
|
showToast(ambiguous ? "Choose the source intent in review" : "Change recorded");
|
|
@@ -5485,6 +5598,7 @@ function installFoundryInspector(options = {}) {
|
|
|
5485
5598
|
selectedElements = [element];
|
|
5486
5599
|
selected = element;
|
|
5487
5600
|
}
|
|
5601
|
+
completeOnboardingStep("selection");
|
|
5488
5602
|
if (!sectionPreferenceTouched) {
|
|
5489
5603
|
const categoryKeys = [
|
|
5490
5604
|
"position",
|
|
@@ -6085,6 +6199,29 @@ function installFoundryInspector(options = {}) {
|
|
|
6085
6199
|
}
|
|
6086
6200
|
});
|
|
6087
6201
|
statusPopover.querySelector("[data-status-retry]").addEventListener("click", () => void hydrateSession());
|
|
6202
|
+
statusPopover.querySelector("[data-status-checklist]").addEventListener("click", () => {
|
|
6203
|
+
localStorage.removeItem(onboardingStorageKey("dismissed"));
|
|
6204
|
+
renderOnboardingChecklist(true);
|
|
6205
|
+
statusPopover.hidden = true;
|
|
6206
|
+
sessionStatus.setAttribute("aria-expanded", "false");
|
|
6207
|
+
});
|
|
6208
|
+
statusPopover.querySelector("[data-status-diagnostics]").addEventListener("click", () => {
|
|
6209
|
+
const diagnostics = createSafeDiagnostics({
|
|
6210
|
+
interfaceTheme: resolvedInterfaceTheme(),
|
|
6211
|
+
runtimeConnected,
|
|
6212
|
+
agentConnected: activeAgentPresence.connected,
|
|
6213
|
+
agentName: activeAgentPresence.presence?.agent?.name,
|
|
6214
|
+
selectedCount: selectedElements.length,
|
|
6215
|
+
recordedChangeCount,
|
|
6216
|
+
latestApplyState
|
|
6217
|
+
});
|
|
6218
|
+
void navigator.clipboard.writeText(JSON.stringify(diagnostics, null, 2));
|
|
6219
|
+
showToast("Privacy-safe diagnostics copied");
|
|
6220
|
+
});
|
|
6221
|
+
statusPopover.querySelector("[data-status-repair]").addEventListener("click", () => {
|
|
6222
|
+
void navigator.clipboard.writeText("npx foundry-design@beta doctor --repair");
|
|
6223
|
+
showToast("Repair command copied");
|
|
6224
|
+
});
|
|
6088
6225
|
interfaceThemeTrigger.addEventListener("click", () => {
|
|
6089
6226
|
if (interfaceThemeMenu.hidden) openInterfaceThemeMenu();
|
|
6090
6227
|
else closeInterfaceThemeMenu();
|
|
@@ -6097,15 +6234,36 @@ function installFoundryInspector(options = {}) {
|
|
|
6097
6234
|
);
|
|
6098
6235
|
changeDock.querySelector(".dock-undo")?.addEventListener("click", () => void replayHistory(-1));
|
|
6099
6236
|
changeDock.querySelector(".dock-review")?.addEventListener("click", () => void openReview());
|
|
6237
|
+
onboarding.querySelector(".onboarding-close")?.addEventListener("click", () => {
|
|
6238
|
+
localStorage.setItem(onboardingStorageKey("dismissed"), "1");
|
|
6239
|
+
onboarding.hidden = true;
|
|
6240
|
+
});
|
|
6100
6241
|
onboarding.querySelector(".onboarding-start")?.addEventListener("click", () => {
|
|
6101
|
-
|
|
6242
|
+
const action = onboarding.querySelector(".onboarding-start")?.dataset.action;
|
|
6243
|
+
if (action === "agent") {
|
|
6244
|
+
void navigator.clipboard.writeText(
|
|
6245
|
+
"Start Foundry for this project and keep listening for Apply with agent requests."
|
|
6246
|
+
);
|
|
6247
|
+
showToast("Listener prompt copied");
|
|
6248
|
+
return;
|
|
6249
|
+
}
|
|
6250
|
+
if (action === "apply" && recordedChangeCount > 0) {
|
|
6251
|
+
onboarding.hidden = true;
|
|
6252
|
+
void openReview();
|
|
6253
|
+
return;
|
|
6254
|
+
}
|
|
6255
|
+
if (action === "done") {
|
|
6256
|
+
onboarding.hidden = true;
|
|
6257
|
+
return;
|
|
6258
|
+
}
|
|
6102
6259
|
onboarding.hidden = true;
|
|
6103
6260
|
inspecting = true;
|
|
6104
6261
|
updateInspectionMode();
|
|
6105
|
-
showToast(
|
|
6262
|
+
showToast(
|
|
6263
|
+
action === "change" ? "Adjust any Inspector value to record a change" : "Select mode stays on \xB7 click any element to begin"
|
|
6264
|
+
);
|
|
6106
6265
|
});
|
|
6107
6266
|
onboarding.querySelector(".onboarding-shortcuts")?.addEventListener("click", () => {
|
|
6108
|
-
localStorage.setItem("__foundry_onboarded", "1");
|
|
6109
6267
|
onboarding.hidden = true;
|
|
6110
6268
|
openCommands();
|
|
6111
6269
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface SafeDiagnosticsInput {
|
|
2
|
+
interfaceTheme: 'light' | 'dark';
|
|
3
|
+
runtimeConnected: boolean;
|
|
4
|
+
agentConnected: boolean;
|
|
5
|
+
agentName?: string;
|
|
6
|
+
selectedCount: number;
|
|
7
|
+
recordedChangeCount: number;
|
|
8
|
+
latestApplyState?: string;
|
|
9
|
+
protocolVersion?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Build useful support state without exposing project content or session credentials. */
|
|
12
|
+
export declare function createSafeDiagnostics(input: SafeDiagnosticsInput): {
|
|
13
|
+
product: string;
|
|
14
|
+
protocolVersion: string;
|
|
15
|
+
interfaceTheme: "light" | "dark";
|
|
16
|
+
connection: {
|
|
17
|
+
agentName?: string | undefined;
|
|
18
|
+
runtime: string;
|
|
19
|
+
agent: string;
|
|
20
|
+
};
|
|
21
|
+
workspace: {
|
|
22
|
+
selectedElementCount: number;
|
|
23
|
+
recordedChangeCount: number;
|
|
24
|
+
latestApplyState: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB;;;;;;;;;;;;;;EAgBhE"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
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;AAu/BD,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,uBAA4B,GACpC,0BAA0B,CAm9K5B"}
|