Repository navigation
Homepage: hero receipt copy, example output, single install block, remove curl text #852
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -171,7 +171,7 @@ | |
| <script defer src="/arcade-boot.js?v=home-light-1"></script> | ||
| <script defer src="/analytics.js?v=home-light-1"></script> | ||
| <script defer src="/utm-capture.js?v=home-light-1"></script> | ||
| <script defer src="/home-key.js?v=home-light-2"></script> | ||
| <script defer src="/home-key.js?v=home-light-3"></script> | ||
| <script defer src="/a11y.js?v=home-light-1"></script> | ||
| </head> | ||
| <body class="home-light site-light"> | ||
|
|
@@ -196,9 +196,10 @@ | |
| <div class="hero-v2-inner"> | ||
| <div class="hero-v2-intro"> | ||
| <h1>Let agents retry safely.</h1> | ||
| <p>One accepted request key permits at most one gateway dispatch to the configured upstream tool and at most one debit. Each finalized or reconciled path has a receipt.</p> | ||
| <p>Each action runs once and leaves a receipt.</p> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For denied, expired, or over-budget requests, the tool runs zero times, while a AGENTS.md reference: AGENTS.md:L62-L71 Useful? React with 👍 / 👎. |
||
| <p class="hero-v2-boundary">One accepted request key permits at most one gateway dispatch to the configured upstream tool and at most one debit. Each finalized or reconciled path has a receipt.</p> | ||
| <div class="hero-v2-actions"> | ||
| <button class="hero-v2-action hero-v2-action-primary" id="home-key-trigger" type="button" aria-controls="home-key-panel" hidden>Get a demo key</button> | ||
| <button class="hero-v2-action hero-v2-action-primary" id="home-key-trigger" type="button" aria-controls="home-key-panel" data-analytics-event="demo_key_click" hidden>Get a demo key</button> | ||
| <noscript><a class="hero-v2-action hero-v2-action-primary" href="/demo-key/">Get a demo key</a></noscript> | ||
| <a class="hero-v2-action hero-v2-action-secondary" href="https://github.com/agentmiddleware/amw-demo" rel="noopener noreferrer">Run the quickstart: amw-demo <span aria-hidden="true">→</span></a> | ||
| </div> | ||
|
|
@@ -219,11 +220,12 @@ <h1>Let agents retry safely.</h1> | |
| python examples/permit_echo_retry.py</code></pre> | ||
| <button id="home-hero-python-copy" type="button" aria-label="Copy Python commands" disabled>Copy</button> | ||
| </div> | ||
| <div class="hero-v2-command-row hero-v2-curl-row"> | ||
| <pre id="home-hero-curl" tabindex="0"><code>curl -s -X POST https://api.thisisatest.tech/v1/demo/keys</code></pre> | ||
| <button id="home-hero-curl-copy" type="button" aria-label="Copy curl command">Copy</button> | ||
| <div class="hero-v2-command-row hero-v2-output" aria-label="Example output"> | ||
| <p>Example output</p> | ||
| <pre tabindex="0"><code>receipt_id: rcpt_7Kq2mX9 | ||
| Same receipt. The tool did not run again.</code></pre> | ||
|
Comment on lines
+225
to
+226
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an upstream tool performs internal retries or the original dispatch has an ambiguous outcome, replaying the same receipt establishes that the gateway did not dispatch again, not that the tool itself did not run again. The page's own receipt definition also says it does not prove the downstream effect, so this output should retain the gateway-scoped wording rather than presenting an unverifiable tool-side conclusion. AGENTS.md reference: AGENTS.md:L62-L71 Useful? React with 👍 / 👎. |
||
| </div> | ||
| <p class="hero-v2-code-note">The button above fills these Python commands with a demo key. With curl, replace both export placeholders using <code>api_key</code> and <code>wallet_id</code> from the response.</p> | ||
| <p class="hero-v2-code-note">Get a demo key to fill the Python commands with your key and wallet ID.</p> | ||
| <p class="hero-v2-copy-status" id="home-hero-copy-status" role="status" aria-live="polite"></p> | ||
| </section> | ||
| <section class="hero-v2-flow" aria-label="Four step request flow"> | ||
|
|
@@ -292,26 +294,13 @@ <h2 id="home-key-title">Get your demo key</h2> | |
|
|
||
| <section class="home-v2-section home-v2-how" id="how-it-works" aria-labelledby="how-title" data-wave="order"> | ||
| <div class="home-v2-section-heading"><p>How it works</p><h2 id="how-title">From demo key to checked receipt</h2></div> | ||
| <div class="home-v2-steps"> | ||
| <article class="home-v2-guide-step"><span class="home-v2-guide-number">1</span><div><h3>Get a demo key</h3><p>Use the button above. Save both <code>api_key</code> and <code>wallet_id</code> for the demo call.</p></div></article> | ||
| <article class="home-v2-guide-step" id="quickstart"><span class="home-v2-guide-number">2</span><div><h3>Set up</h3><p>Run the Python example with your demo key and wallet. It needs Python 3.10 or newer.</p> | ||
| <div class="home-code-panel"> | ||
| <div class="home-code-toolbar"><span>Python</span><button id="home-copy-quickstart" type="button" disabled>Copy setup</button></div> | ||
| <pre class="home-code-scroll" tabindex="0"><code id="home-quickstart-code" tabindex="-1">git clone https://github.com/agentmiddleware/amw-demo.git | ||
| cd amw-demo | ||
| python3 -m venv .venv | ||
| source .venv/bin/activate | ||
| pip install -e . | ||
| export AMW_API_KEY='YOUR_DEMO_KEY' | ||
| export AMW_WALLET_ID='YOUR_WALLET_ID' | ||
| python examples/permit_echo_retry.py</code></pre> | ||
| <p class="home-code-help" id="home-copy-status" role="status" aria-live="polite">Get a demo key to fill in the two export lines.</p> | ||
| </div> | ||
| </div></article> | ||
| <article class="home-v2-guide-step"><span class="home-v2-guide-number">3</span><div><h3>First call returns a receipt</h3><p>The example creates a permit and calls <code>partner.echo</code> through the gateway. It prints a receipt ID for the result.</p></div></article> | ||
| <article class="home-v2-guide-step"><span class="home-v2-guide-number">4</span><div><h3>Retry with the same request key</h3><p>For an accepted request key on the configured upstream tool, a retry with the same key returns the original receipt instead of dispatching again. The receipt does not prove what happened inside the tool.</p></div></article> | ||
| <article class="home-v2-guide-step"><span class="home-v2-guide-number">5</span><div><h3>Check the receipt offline</h3><p>The example fetches the receipt and public keys, then checks the signature on your machine. <a href="/proof/">See a published sample and verifier.</a></p></div></article> | ||
| </div> | ||
| <ul class="home-v2-steps"> | ||
| <li>Get a demo key and save the API key and wallet ID.</li> | ||
| <li id="quickstart">Set the key and wallet ID in the Python commands above, then run the example.</li> | ||
| <li>The first call creates a permit and prints the receipt ID.</li> | ||
| <li>For an accepted request key on the configured upstream tool, a retry with the same key returns the original receipt instead of dispatching again.</li> | ||
| <li>Check the receipt signature offline. <a href="/proof/">See a published sample and verifier.</a></li> | ||
| </ul> | ||
| </section> | ||
|
|
||
| <section class="home-v2-section home-v2-limits" id="limits" aria-labelledby="limits-title" data-wave="quiet"> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2669,6 +2669,12 @@ body.home-light .hero-v2-intro > p { | |
| font-size: 1.1875rem; | ||
| letter-spacing: -0.018em; | ||
| } | ||
| body.home-light .hero-v2-intro > .hero-v2-boundary { | ||
| margin-top: 5px; | ||
| font-size: 0.875rem; | ||
| line-height: 1.5; | ||
| letter-spacing: 0; | ||
| } | ||
| body.home-light .hero-v2-actions { | ||
| display: flex; | ||
| flex-wrap: wrap; | ||
|
|
@@ -2744,7 +2750,7 @@ body.home-light .hero-v2-tab-disabled { | |
| } | ||
| body.home-light .hero-v2-tab-disabled span { | ||
| padding: 3px 6px; | ||
| border: 1px solid var(--home-line); | ||
| border: 1px solid #6b7280; | ||
| border-radius: 4px; | ||
| font-size: 0.625rem; | ||
| } | ||
|
|
@@ -2771,23 +2777,29 @@ body.home-light .hero-v2-command-row button { | |
| cursor: pointer; | ||
| } | ||
| body.home-light .hero-v2-command-row button:disabled { cursor: not-allowed; opacity: 0.55; } | ||
| body.home-light .hero-v2-curl-row { | ||
| margin: 18px 23px 0; | ||
| body.home-light .hero-v2-output { | ||
| margin: 16px 23px 0; | ||
| border-top: 1px solid var(--home-line); | ||
| } | ||
| body.home-light .hero-v2-curl-row pre { padding: 14px 64px 0 0; line-height: 1.375rem; } | ||
| body.home-light .hero-v2-curl-row button { top: 6px; right: -8px; } | ||
| body.home-light .hero-v2-output p { | ||
| margin: 12px 0 0; | ||
| color: var(--home-muted); | ||
| font-size: 0.75rem; | ||
| } | ||
| body.home-light .hero-v2-command-row.hero-v2-output pre { | ||
| padding: 8px 0 0; | ||
| line-height: 1.5; | ||
| white-space: pre-wrap; | ||
| } | ||
| body.home-light .hero-v2-code-note { | ||
| margin: 16px 23px 0; | ||
| max-width: none; | ||
| color: var(--home-muted); | ||
| font-size: 0.75rem; | ||
| } | ||
| body.home-light .hero-v2-copy-status { | ||
| position: absolute; | ||
| right: 23px; | ||
| bottom: 7px; | ||
| margin: 0; | ||
| margin: 6px 23px 0; | ||
| min-height: 1rem; | ||
| color: var(--home-muted); | ||
| font-size: 0.6875rem; | ||
| } | ||
|
|
@@ -3031,78 +3043,33 @@ body.home-light .home-v2-section-heading > p { | |
| font-weight: 600; | ||
| } | ||
| body.home-light .home-v2-section-heading h2 { margin: 0 0 30px; font-size: 2.375rem; } | ||
| body.home-light .home-v2-guide-step { | ||
| display: grid; | ||
| grid-template-columns: 34px minmax(0, 1fr); | ||
| gap: 18px; | ||
| padding: 20px 0; | ||
| border-top: 1px solid var(--home-line); | ||
| body.home-light .home-v2-steps { | ||
| margin: 0; | ||
| padding: 0; | ||
| list-style: none; | ||
| } | ||
| body.home-light .home-v2-guide-number { | ||
| body.home-light .home-v2-steps li { | ||
| display: grid; | ||
| place-items: center; | ||
| width: 32px; | ||
| height: 32px; | ||
| border: 1px solid var(--home-line); | ||
| border-radius: 6px; | ||
| grid-template-columns: 24px minmax(0, 1fr); | ||
| gap: 12px; | ||
| padding: 16px 0; | ||
| border-top: 1px solid var(--home-line); | ||
| color: var(--home-muted); | ||
| font-size: 0.75rem; | ||
| font-weight: 600; | ||
| font-size: 0.9375rem; | ||
| line-height: 1.6; | ||
| } | ||
| body.home-light .home-v2-steps li::before { | ||
| content: "✓"; | ||
| color: var(--home-blue); | ||
| font-weight: 700; | ||
| } | ||
| body.home-light .home-v2-guide-step h3 { margin: 2px 0 8px; font-size: 1.125rem; } | ||
| body.home-light .home-v2-guide-step p, | ||
| body.home-light .home-v2-limits > p, | ||
| body.home-light .home-v2-source > p { | ||
| max-width: 76ch; | ||
| color: var(--home-muted); | ||
| font-size: 0.9375rem; | ||
| line-height: 1.6; | ||
| } | ||
| body.home-light .home-code-panel { | ||
| max-width: 850px; | ||
| margin-top: 18px; | ||
| overflow: hidden; | ||
| border: 1px solid var(--home-line); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checklist link breaks grid layoutMedium Severity The How it works checklist lays out each Additional Locations (1)Reviewed by Cursor Bugbot for commit eb81a90. Configure here. |
||
| border-radius: 10px; | ||
| background: var(--home-soft); | ||
| box-shadow: none; | ||
| } | ||
| body.home-light .home-code-toolbar { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: space-between; | ||
| gap: 1rem; | ||
| min-height: 46px; | ||
| padding: 0 18px; | ||
| border-bottom: 1px solid var(--home-line); | ||
| font-size: 0.75rem; | ||
| font-weight: 600; | ||
| } | ||
| body.home-light .home-code-toolbar button { | ||
| padding: 5px 9px; | ||
| border: 1px solid var(--home-line); | ||
| border-radius: 5px; | ||
| background: var(--home-bg); | ||
| color: var(--home-muted); | ||
| font: 600 0.6875rem "Public Sans", sans-serif; | ||
| cursor: pointer; | ||
| } | ||
| body.home-light .home-code-toolbar button:disabled { cursor: not-allowed; opacity: 0.55; } | ||
| body.home-light .home-code-scroll { | ||
| margin: 0; | ||
| overflow-x: auto; | ||
| padding: 18px 23px; | ||
| color: var(--home-text); | ||
| font-size: 0.8125rem; | ||
| line-height: 1.55; | ||
| } | ||
| body.home-light .home-code-help { | ||
| margin: 0; | ||
| padding: 0.55rem 1.4rem; | ||
| border-top: 1px solid var(--home-line); | ||
| color: var(--home-muted); | ||
| font-size: 0.75rem; | ||
| } | ||
| body.home-light .home-v2-section a { text-decoration: underline; } | ||
| body.home-light .home-v2-source { padding-bottom: 90px; } | ||
| body.home-light .home-v2-source a { overflow-wrap: anywhere; } | ||
|
|
@@ -3130,15 +3097,12 @@ body.home-light .home-v2-source a { overflow-wrap: anywhere; } | |
| align-self: flex-end; | ||
| margin: 8px 14px 0; | ||
| } | ||
| body.home-light .hero-v2-curl-row { margin-top: 12px; } | ||
| body.home-light .hero-v2-code-note { margin-top: 12px; } | ||
| body.home-light .hero-v2-copy-status { position: static; margin: 6px 23px 0; } | ||
| body.home-light .hero-v2-flow { grid-template-columns: minmax(0, 1fr); } | ||
| body.home-light .hero-v2-step { min-height: 0; } | ||
| body.home-light .home-v2-glossary { grid-template-columns: minmax(0, 1fr); min-height: 0; } | ||
| body.home-light .home-v2-glossary article { min-height: 0; } | ||
| body.home-light .home-v2-section { padding-top: 50px; padding-bottom: 50px; } | ||
| body.home-light .home-v2-guide-step { gap: 12px; } | ||
| body.home-light .home-key-drawer { padding: 84px 24px 24px; } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import assert from "node:assert/strict"; | ||
| import { readFileSync } from "node:fs"; | ||
| import test from "node:test"; | ||
| import { createContext, runInContext } from "node:vm"; | ||
|
|
||
| const script = readFileSync(new URL("./analytics.js", import.meta.url), "utf8"); | ||
| const homeHtml = readFileSync(new URL("./index.html", import.meta.url), "utf8"); | ||
|
|
||
| function analyticsPage(analyticsEnabled) { | ||
| const sent = []; | ||
| let click; | ||
| const context = createContext({ | ||
| document: { | ||
| addEventListener(name, listener) { | ||
| assert.equal(name, "click"); | ||
| click = listener; | ||
| }, | ||
| }, | ||
| window: analyticsEnabled ? { | ||
| va(...args) { sent.push(JSON.parse(JSON.stringify(args))); }, | ||
| } : {}, | ||
| }); | ||
| runInContext(script, context, { filename: "analytics.js" }); | ||
| return { | ||
| sent, | ||
| click(eventName) { | ||
| click({ | ||
| target: { | ||
| closest(selector) { | ||
| assert.equal(selector, "[data-analytics-event]"); | ||
| return eventName ? { dataset: { analyticsEvent: eventName } } : null; | ||
| }, | ||
| }, | ||
| }); | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| test("homepage demo key button emits one existing analytics event per click", () => { | ||
| assert.match(homeHtml, /<button[^>]*id="home-key-trigger"[^>]*data-analytics-event="demo_key_click"[^>]*>/); | ||
| const page = analyticsPage(true); | ||
| page.click("demo_key_click"); | ||
| assert.deepEqual(page.sent, [["event", { name: "demo_key_click" }]]); | ||
| }); | ||
|
|
||
| test("analytics stays silent without opt in and rejects unknown event names", () => { | ||
| const disabled = analyticsPage(false); | ||
| disabled.click("demo_key_click"); | ||
| assert.deepEqual(disabled.sent, []); | ||
|
|
||
| const enabled = analyticsPage(true); | ||
| enabled.click("receipt_verified"); | ||
| enabled.click(""); | ||
| assert.deepEqual(enabled.sent, []); | ||
| }); |


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The deployment caches
analytics.jsfor seven days, but the homepage still loads it with the existing?v=home-light-1token. Returning visitors with the prior script cached will therefore keep the old allowlist and silently rejectdemo_key_clickuntil expiry; bump the homepage analytics URL when adding this allowlist entry.Useful? React with 👍 / 👎.