Skip to content

Reagan/make shopping experience awesome#442

Merged
Cheggin merged 17 commits into
mainfrom
reagan/make-shopping-experience-awesome
May 26, 2026
Merged

Reagan/make shopping experience awesome#442
Cheggin merged 17 commits into
mainfrom
reagan/make-shopping-experience-awesome

Conversation

@Cheggin
Copy link
Copy Markdown
Collaborator

@Cheggin Cheggin commented May 26, 2026

Summary by cubic

Rebuilt the shopping/options picker for faster, clearer choices with one‑click picks, verified sources, and a cleaner receipt. Picker/ask state now derives from the transcript (including late replies), re‑hydrates after failed local submits, and overrides any cache to avoid stale views.

  • New Features

    • Per‑card Choose button. Single‑select submits instantly; multi‑select shows Confirm only when valid. Choose stays enabled after a card click.
    • Shared‑site header with favicon; per‑card favicons when mixed. “View on {site}” opens via shell:open-external.
    • Post‑submit receipt now matches card styling: solid border, 44px thumb, favicon + bold site + optional price; no “Chose:” prefix. Chosen state is reconstructed from the next user reply, even if it arrives after first render; re‑runs hydration after a failed local submit; transcript‑derived state overrides cache bootstrap; cancelled state remains.
    • “Other” is a small link (not a card) and defaults off; it focuses the chat input.
    • Parser now requires id, image, title, url, site; url and image must be absolute http(s). Decorative Airbnb badge art is dropped; missing fields are omitted (no filler “—”). Non‑http(s) values are rejected at parse time.
    • HTML blocks: added receipt/comparison/status patterns, a rule‑of‑thumb (3+ concrete facts → emit a compact ```html block), small vertical spacing for readability, and a dark‑mode rule to use the palette shadow color (no accent‑colored structural shadows).
    • Hardened transcript parsing for “Other” replies: AskForm preserves comma‑containing text; OptionList drops unlabeled “Other” replies instead of defaulting to section 0.
    • AskForm/OptionList visuals: remove outer card chrome; drop tracked uppercase chips; custom radio/checkbox; tighter option stacking. AskForm checkbox uses a theme‑aware CSS mask for a clear checkmark in light/dark.
  • Migration

    • Emit url (absolute http(s)) and human site for every option (e.g., “Amazon”, “Airbnb”; no TLD).
    • Set allowOther: true only when you really want it; default is now false.
    • Use real listing/product hero image (absolute http(s)); skip badges/favicons and Airbnb AirbnbPlatformAssets/GuestFavorite/orthographic-images.
    • For dense shopping data (carts, prices, delivery windows), prefer compact ```html blocks per the updated guidance.

Written for commit d658fb1. Summary will update on new commits. Review in cubic

Cheggin and others added 5 commits May 26, 2026 12:18
The Instacart cart confirmation exposed a compact set of page facts, but the HTML guidance mostly named broad artifact categories. Add receipt-style patterns to the interaction skill and pin the prompt nudge so future agents treat shopping and cart confirmations as scannable HTML candidates.

Constraint: Existing renderer accepts static sandboxed HTML from fenced blocks
Rejected: Add renderer heuristics for prose summaries | model-side guidance is narrower and avoids changing transcript rendering
Confidence: high
Scope-risk: narrow
Directive: Keep HTML triggers tied to dense structured facts; short conversational replies should remain markdown
Tested: npm run test -- tests/unit/hl/skillIndexPrompt.test.ts
Tested: npm run typecheck
Tested: npm run lint
Not-tested: Live Claude Code shopping run after prompt update
Co-authored-by: OmX <omx@oh-my-codex.dev>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 10 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread app/src/renderer/hub/chat-v2/OptionList.tsx Outdated
Cheggin and others added 4 commits May 26, 2026 12:31
The dark-mode HTML guidance allowed gold accents to become large frame shadows, which made comparison artifacts feel too loud. Constrain large offset shadows to the palette shadow color and keep accents as small highlights.

Constraint: Dark theme already defines cream as the palette shadow color
Rejected: Remove hard shadows entirely | the house style depends on hard offset shadows
Confidence: high
Scope-risk: narrow
Directive: Do not use accent colors for large structural shadows in dark-mode HTML artifacts
Tested: npm run test -- tests/unit/hl/skillIndexPrompt.test.ts
Tested: npm run typecheck
Tested: npm run lint
Tested: git diff --check
Not-tested: Live agent-generated dark-mode HTML artifact after prompt update
Co-authored-by: OmX <omx@oh-my-codex.dev>
The disabled rule `isConfirmed && !multiSelect` conflated 'currently
selected' with 'already submitted', so clicking a card to select it
then clicking Choose was impossible — the button disabled itself the
moment the card became selected. The parent-level `disabled=locked`
already handles post-submit lockdown.
Mirrors how Codex's rollout/state split works: the conversation log is
the source of truth, and the UI reconstructs derived state from it
instead of maintaining a parallel cache.

ChatTranscript now forwards each turn's next-turn user reply as
nextUserText down through ChatTurn into OptionList and AskForm. Each
component reverses its outbound message format ('Selected from options:'
and 'Answered:') to rebuild the selected ids without consulting any
client-side persistence layer. Tab-switch optimism still routes through
the in-memory submission cache, which is intentionally not persisted.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread app/src/renderer/hub/chat-v2/AskForm.tsx Outdated
Comment thread app/src/renderer/hub/chat-v2/OptionList.tsx Outdated
AskForm: 'Other: <text>' answers can contain commas, so splitting on
/,\s+/ corrupted them. Locate the Other segment, peel the rest of the
line off as its text, and only split predefined labels.

OptionList: in multi-section pickers, drop Other replies that lack a
matching label prefix instead of defaulting to section 0 — silent
mis-attribution risked showing the wrong section as chosen.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/renderer/hub/chat-v2/AskForm.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/AskForm.tsx:418">
P1: The new `Other` parsing assumes `Other` is the final value, so when `Other` appears first (a valid serialized order), later options are lost during transcript reconstruction.</violation>
</file>

<file name="app/src/renderer/hub/chat-v2/OptionList.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/OptionList.tsx:849">
P2: Multi-section `Other:` selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

let valuesPart = valuesStr;
let otherTail: string | null = null;
const otherIdx = (() => {
const leading = valuesPart.match(/^Other(?::|$)/);
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The new Other parsing assumes Other is the final value, so when Other appears first (a valid serialized order), later options are lost during transcript reconstruction.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/renderer/hub/chat-v2/AskForm.tsx, line 418:

<comment>The new `Other` parsing assumes `Other` is the final value, so when `Other` appears first (a valid serialized order), later options are lost during transcript reconstruction.</comment>

<file context>
@@ -406,19 +406,33 @@ export function deriveAskSubmission(
+    let valuesPart = valuesStr;
+    let otherTail: string | null = null;
+    const otherIdx = (() => {
+      const leading = valuesPart.match(/^Other(?::|$)/);
+      if (leading) return 0;
+      const m = valuesPart.match(/,\s+Other(?::|$)/);
</file context>
Fix with Cubic

Comment on lines +849 to +850
if (idx < 0) continue;
target = idx;
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Multi-section Other: selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/renderer/hub/chat-v2/OptionList.tsx, line 849:

<comment>Multi-section `Other:` selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.</comment>

<file context>
@@ -831,18 +831,23 @@ export function deriveSubmissionFromTranscript(
       const label = labelMatch?.[1].trim();
       const idx = label ? sections.findIndex((s) => s.label === label) : -1;
-      target = idx >= 0 ? idx : 0;
+      if (idx < 0) continue;
+      target = idx;
     }
</file context>
Suggested change
if (idx < 0) continue;
target = idx;
if (idx < 0) {
const unlabeled = sections.filter((s) => !s.label);
if (unlabeled.length !== 1) continue;
target = sections.findIndex((s) => !s.label);
} else {
target = idx;
}
Fix with Cubic

Cheggin added 2 commits May 26, 2026 13:33
Remove the per-question card background/border/padding so the form
sits in the chat flow instead of inside a boxed surface. Drop the
monospace tracked-uppercase header chip on questions and the same
treatment on post-answer labels — they now read as plain sans like
the rest of the chat. Custom radio/checkbox replace the native
controls (single filled circle on check, no doubled-up ring), and
the option row's gap is split so descriptions tuck under the title
instead of floating 10px below.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/renderer/hub/chat-v2/AskForm.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/AskForm.tsx:418">
P1: The new `Other` parsing assumes `Other` is the final value, so when `Other` appears first (a valid serialized order), later options are lost during transcript reconstruction.</violation>
</file>

<file name="app/src/renderer/hub/chat-v2/OptionList.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/OptionList.tsx:849">
P2: Multi-section `Other:` selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread app/src/renderer/hub/chat-v2/askForm.css Outdated
The previous SVG bg-image had a hard-coded #111 stroke, which vanished
in light mode where --color-fg-primary (the checked fill) is also
near-black. Switching to a mask + var(--color-bg-base) makes the stroke
always contrast with the fill in both themes.
@Cheggin
Copy link
Copy Markdown
Collaborator Author

Cheggin commented May 26, 2026

@cubic review

@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented May 26, 2026

@cubic review

@Cheggin I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 17 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/renderer/hub/chat-v2/AskForm.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/AskForm.tsx:418">
P1: The new `Other` parsing assumes `Other` is the final value, so when `Other` appears first (a valid serialized order), later options are lost during transcript reconstruction.</violation>
</file>

<file name="app/src/renderer/hub/chat-v2/OptionList.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/OptionList.tsx:849">
P2: Multi-section `Other:` selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread app/src/renderer/hub/chat-v2/htmlBlocks.ts
Comment thread app/src/renderer/hub/chat-v2/AskForm.tsx
Cheggin added 2 commits May 26, 2026 14:01
Renderer hands url to shell.openExternal, which rejects non-http(s),
and image goes into <img src> — relative or javascript:/data URLs
from a model-emitted block shouldn't be navigated to or loaded.
Validate at parse time so bad options drop with the rest of the
fail-shut checks instead of failing at click time.
useState(() => …) runs once. During session replay the AskForm/OptionList
turn lands before the user-reply turn, so the initial nextUserText is
null and the picker mounts as unsubmitted — even though the answer is
already on the transcript and arrives a few re-renders later. Add a
useEffect that hydrates state when transcriptSubmission becomes
non-null and the user hasn't already submitted locally.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/renderer/hub/chat-v2/AskForm.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/AskForm.tsx:418">
P1: The new `Other` parsing assumes `Other` is the final value, so when `Other` appears first (a valid serialized order), later options are lost during transcript reconstruction.</violation>
</file>

<file name="app/src/renderer/hub/chat-v2/OptionList.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/OptionList.tsx:849">
P2: Multi-section `Other:` selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread app/src/renderer/hub/chat-v2/OptionList.tsx Outdated
The late-hydration effect was guarded on `submitted`, but bootstrap
from the in-memory cache also sets submitted=true — so a stale cache
hit would permanently block transcript hydration even though the
transcript is the durable source of truth. Switch to a localSubmitRef
that flips only on a real user submit in this mount, so cache-derived
state still yields to a later-arriving transcript.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/renderer/hub/chat-v2/AskForm.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/AskForm.tsx:418">
P1: The new `Other` parsing assumes `Other` is the final value, so when `Other` appears first (a valid serialized order), later options are lost during transcript reconstruction.</violation>
</file>

<file name="app/src/renderer/hub/chat-v2/OptionList.tsx">

<violation number="1" location="app/src/renderer/hub/chat-v2/OptionList.tsx:849">
P2: Multi-section `Other:` selections are dropped when section labels are missing, so valid historical selections may not round-trip from transcript.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread app/src/renderer/hub/chat-v2/OptionList.tsx Outdated
localSubmitRef was a ref, so clearing it on submit failure didn't
trigger a re-render or re-run the hydration effect. If the transcript
had already arrived before the submit attempt, it would never be
applied. Promote it to state so the effect's dependency list reacts
to the flip back to false.
@Cheggin Cheggin merged commit f073b75 into main May 26, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant