From e290baa31bbea730aec2926d758f9e9612422598 Mon Sep 17 00:00:00 2001 From: ZdenekSrotyr <139972147+ZdenekSrotyr@users.noreply.github.com> Date: Thu, 14 May 2026 20:41:04 +0200 Subject: [PATCH] =?UTF-8?q?release:=200.54.14=20=E2=80=94=20changelog=20re?= =?UTF-8?q?pair=20+=20post-#305=20dead-code=20sweep=20(#309)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cuts 0.54.14. Repairs the [Unreleased] changelog state left by three PRs that merged since v0.54.13 without proper changelog hygiene, sweeps dead code orphaned by #305 and earlier PRs, and bumps the version. - CHANGELOG: #307 bullets moved out of the released [0.54.10] section into [Unreleased]; backfilled missing entries for #305 (Removed) and #308 (Changed); [Unreleased] -> [0.54.14] release cut. - pyproject.toml: 0.54.13 -> 0.54.14. - app/web/router.py: removed orphaned gws_oauth / instance_admin_email / connector_prompts keys from the shared _build_context ctx dict. - app/web/templates/home_not_onboarded.html: swept dead connector-tile, automode, and setup-collapsible/minimize CSS + the orphaned JS click-wiring. --- CHANGELOG.md | 135 ++++-- app/web/router.py | 26 +- app/web/templates/home_not_onboarded.html | 473 +--------------------- pyproject.toml | 2 +- 4 files changed, 98 insertions(+), 538 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0327d44..e9aefb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,98 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C ## [Unreleased] +## [0.54.14] — 2026-05-14 + +### Changed +- **Marketplace submission surfaces — clearer CTA + fuller guides + (#308).** The curated-tab action-row CTA now reads "Submit a skill + or plugin" (was "Submit a plugin") — skills are first-class on the + curated shelf — with the same wording mirrored in the empty-state + JS and the route titles so the surfaces can't drift. The curated + guide (`/marketplace/guide/curated`) grows from a 4-line stub into + a 3-step walkthrough of the Named Curator handoff plus a + `.guide-fastpath` callout pointing lighter submissions at the Flea + Market; the flea guide (`/marketplace/guide/flea`) grows from a + 3-line stub into a 4-step walkthrough of the `/store/new` + self-serve flow and its automated guardrails (manifest, + content-quality, and prompt-injection scans). + +### Fixed +- **`agnes refresh-marketplace` now enables stack plugins in workspace + settings (#307).** The reconcile step previously stopped at `claude plugin + install --scope project`, which only writes the global plugin registry + (`~/.claude/plugins/installed_plugins.json`). Without a corresponding + entry in the workspace `.claude/settings.json` `enabledPlugins` map, + Claude Code treats every installed stack plugin as disabled — `/plugins` + hides them from the active section and their slash commands, skills, + and agents are unreachable. Refresh now writes + `"@agnes": true` to the workspace settings file after install + and update, treating the user's marketplace stack as the source of + truth and re-enabling any plugin that a prior local `claude plugin + disable` had turned off. +- **Runtime CLI commands now work on Initial Workspace Template + (override) workspaces (#307).** The `.claude/init-complete` sentinel + carrying `override: true` previously short-circuited **every** + Agnes writer to `.claude/`, which trapped admin-templated workspaces + at a stale snapshot: `agnes refresh-marketplace` couldn't write the + `enabledPlugins` map (the fix above stayed inert), and + `agnes self-upgrade`'s `maybe_refresh_claude_hooks` couldn't migrate + workspaces to new Agnes hook layouts. The sentinel was meant to gate + **init-time** skip only — let admins ship the *initial* `.claude/` + contents — not to lock the workspace permanently. The override check + moves from inside the writers + (`cli/lib/hooks.py::install_claude_hooks`, + `cli/lib/hooks.py::maybe_refresh_claude_hooks`, + `cli/lib/commands.py::install_claude_commands`, + `cli/commands/refresh_marketplace.py::_enable_plugins_in_workspace_settings`) + to the init-time call site that always was the right place + (`cli/commands/init.py::init`, `if not override_active:`). Init-time + behavior unchanged — `agnes init` on an override workspace still + defers the workspace skeleton to admin's template. Admin custom hooks + survive runtime refresh: Agnes only rewrites entries matching + `_OUR_COMMAND_MARKERS` (`agnes self-upgrade` / `agnes pull` / ... + substring set in `cli/lib/hooks.py`); foreign commands fall through + unchanged, same contract as in default workspaces. Existing override + workspaces auto-converge on the next `agnes self-upgrade` (which + fires from every SessionStart hook); no manual operator action + needed. Retracts the earlier *"full responsibility transfer; future + Agnes hook fixes will NOT auto-propagate"* contract documented in + the `[0.54.10]` `### Internal — risk-accepted by design` bullets — + that scope was wider than the feature's actual intent. + +### Removed +- **`/home` connectors block dropped — the onboarding flow covers it + (#305).** The dedicated `
` section + on `/home` (three tiles — Asana / Google Workspace / Atlassian — each + with a "Copy prompt" button) duplicated content the install-hero's + Step 4 clipboard payload already inlines via + `app/web/setup_instructions.py::_connectors_block`: users walking the + setup script visit every connector inline. The install-hero lead + paragraph now names the connector families so the benefit stays + visible before kick-off. The per-instance "Email admin" mailto CTA — + previously gated inside the GWS tile when an operator contact email + was set and GWS OAuth was unconfigured — was dropped along with the + block; the GWS connector setup prompt still tells the user to ask an + admin, but without the pre-filled per-instance contact address. + +### Internal +- Post-#305 cleanup. Removed the now-orphaned `gws_oauth`, + `instance_admin_email`, and `connector_prompts` keys from the shared + `_build_context` ctx dict in `app/web/router.py` — no template + referenced them once the connectors block was dropped, and + `connector_prompts` was calling `all_connector_prompts()` on every + page render app-wide. Swept the dead `.connector-tile*`, + `.connector-copy`, `.connector-preview`, `.copy-next-hint`, + `.time-badge`, `.gating-note`, `.email-admin`, `.card-mini-cmd`, and + `.connector-head` CSS rules plus the orphaned `.connector-copy` + click-wiring JS from `home_not_onboarded.html`. Also removed the + dead `.automode-*`, `.setup-collapsible`, and `.setup-minimize` + CSS blocks and the `setupMinimizeToggle` / `data-setup-minimized` + JS handler from the same template — the `
` + sections and the "Minimize setup view" toggle they styled were + removed by earlier PRs (#243 onward), leaving the whole + minimize-mode machinery unreachable. + ## [0.54.13] — 2026-05-14 ### Security @@ -189,47 +281,6 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C fine because `.mp-type-row` contributes its own 24px. ### Fixed -- **`agnes refresh-marketplace` now enables stack plugins in workspace - settings.** The reconcile step previously stopped at `claude plugin - install --scope project`, which only writes the global plugin registry - (`~/.claude/plugins/installed_plugins.json`). Without a corresponding - entry in the workspace `.claude/settings.json` `enabledPlugins` map, - Claude Code treats every installed stack plugin as disabled — `/plugins` - hides them from the active section and their slash commands, skills, - and agents are unreachable. Refresh now writes - `"@agnes": true` to the workspace settings file after install - and update, treating the user's marketplace stack as the source of - truth and re-enabling any plugin that a prior local `claude plugin - disable` had turned off. -- **Runtime CLI commands now work on Initial Workspace Template - (override) workspaces.** The `.claude/init-complete` sentinel - carrying `override: true` previously short-circuited **every** - Agnes writer to `.claude/`, which trapped admin-templated workspaces - at a stale snapshot: `agnes refresh-marketplace` couldn't write the - `enabledPlugins` map (the fix above stayed inert), and - `agnes self-upgrade`'s `maybe_refresh_claude_hooks` couldn't migrate - workspaces to new Agnes hook layouts. The sentinel was meant to gate - **init-time** skip only — let admins ship the *initial* `.claude/` - contents — not to lock the workspace permanently. The override check - moves from inside the writers - (`cli/lib/hooks.py::install_claude_hooks`, - `cli/lib/hooks.py::maybe_refresh_claude_hooks`, - `cli/lib/commands.py::install_claude_commands`, - `cli/commands/refresh_marketplace.py::_enable_plugins_in_workspace_settings`) - to the init-time call site that always was the right place - (`cli/commands/init.py::init`, `if not override_active:`). Init-time - behavior unchanged — `agnes init` on an override workspace still - defers the workspace skeleton to admin's template. Admin custom hooks - survive runtime refresh: Agnes only rewrites entries matching - `_OUR_COMMAND_MARKERS` (`agnes self-upgrade` / `agnes pull` / ... - substring set in `cli/lib/hooks.py`); foreign commands fall through - unchanged, same contract as in default workspaces. Existing override - workspaces auto-converge on the next `agnes self-upgrade` (which - fires from every SessionStart hook); no manual operator action - needed. Retracts the earlier *"full responsibility transfer; future - Agnes hook fixes will NOT auto-propagate"* contract documented in - the `### Internal — risk-accepted by design` bullets immediately - below — that scope was wider than the feature's actual intent. - **Store guardrails — post-#290 follow-up.** Admin Rescan still writes `status='blocked_inline'` (the only post-v30 producer of that status). Re-add `blocked_inline` to the admin queue's "Needs review" filter chip and to `TERMINAL_BLOCKED_STATUSES` in the bundle-purge job, so a rescan-produced row surfaces in the default operator view and its bundle gets swept by the TTL purge instead of lingering on disk indefinitely. Documents the rescan-only asymmetry inline (chip + purge tuple + new code comments). - Stale doc strings referring to the pre-#290 `blocked_inline` quota counter on `app/api/store.py` spam-quota comment, `app/instance_config.py::get_guardrails_blocked_quota_per_day` docstring, and the operator-facing hint in `/admin/server-config` (`blocked_quota_per_day`). All three now correctly describe the narrowed `blocked_llm + review_error` counter that #290 actually shipped. @@ -270,7 +321,7 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C ### Internal — risk-accepted by design (see Initial Workspace Template feature) - `agnes init --force` on override workspaces does NOT back up `CLAUDE.md` (no `CLAUDE.md.bak.` file). Source of truth is the admin's Git repo; recovery is `git log` / `git checkout`. Not a regression of #164. - `.claude/CLAUDE.local.md` IS overwritten by override extraction when the admin's repo includes it. The default-mode "never overwrite CLAUDE.local.md" promise is a default-mode promise; override mode hands full file-level control to admin. Documented. -- `cli/lib/override.py::is_override_workspace` gates the **init-time** skip block in `cli/commands/init.py` (the `if not override_active:` branch). Runtime CLI commands (`agnes refresh-marketplace`, `agnes self-upgrade`'s `maybe_refresh_claude_hooks`) do NOT consult the sentinel and keep the workspace in sync — see the `### Fixed` entry "Runtime CLI commands now work on Initial Workspace Template workspaces" above for the full contract. +- `cli/lib/override.py::is_override_workspace` gates the **init-time** skip block in `cli/commands/init.py` (the `if not override_active:` branch). Runtime CLI commands (`agnes refresh-marketplace`, `agnes self-upgrade`'s `maybe_refresh_claude_hooks`) do NOT consult the sentinel and keep the workspace in sync — see the `### Fixed` entry "Runtime CLI commands now work on Initial Workspace Template workspaces" in the `[0.54.14]` release notes for the full contract. - `app/api/marketplaces.py::_persist_token` removed; both marketplaces and the new initial-workspace endpoint now route through the shared `app/secrets.py::persist_overlay_token` helper, which wraps the `.env_overlay` read-modify-write in a process-wide `threading.Lock`. Closes a pre-existing race where two concurrent `/admin/marketplaces` Save clicks could clobber each other's PATs on the overlay file. ## [0.54.8] — 2026-05-13 diff --git a/app/web/router.py b/app/web/router.py index cdffd49..1d492d5 100644 --- a/app/web/router.py +++ b/app/web/router.py @@ -433,9 +433,9 @@ def _build_context( server_host = request.url.netloc ca_pem = _read_agnes_ca_pem() - # Connector prompts wired through so step 9 inlines the same text - # the /home tiles render. all_connector_prompts() reads operator - # GWS OAuth config so the GCP-frictionless branch fires when the + # Connector prompts wired through so the setup script's connector + # step inlines them. all_connector_prompts() reads operator GWS + # OAuth config so the GCP-frictionless branch fires when the # admin has provisioned a shared client_id+secret. _connector_prompts = all_connector_prompts( gws_oauth=get_gws_oauth_credentials(), @@ -471,14 +471,6 @@ def _build_context( # single env flip routes the primary nav target between /home # (state-aware landing) and /dashboard (legacy table inventory). "home_route": _resolved_home_route(), - # Pre-configured Google Workspace CLI OAuth client for the - # /home connector prompt. {} when unset → template falls back - # to manual `gws auth setup`. See app.instance_config docstring. - "gws_oauth": get_gws_oauth_credentials(), - # Operator-facing contact email used by the /home GWS connector - # tile's "Email admin" mailto button. Empty string hides the - # button — template guards with `{% if instance_admin_email %}`. - "instance_admin_email": get_instance_admin_email(), # Branding: `instance_name` is the deploying org's display name # (page titles); `instance_brand` is the product name used in body # copy and CTAs ("Setup {brand}", "{brand} runs SELECT…"); `workspace_dir` @@ -489,18 +481,6 @@ def _build_context( "instance_name": get_instance_name(), "instance_brand": get_instance_brand(), "workspace_dir": get_workspace_dir_name(), - # Resolved connector setup prompts — single source of truth for - # both the /home "Copy prompt" tiles and the main setup script - # (app/web/setup_instructions.py inlines them in step 9). The - # gws prompt branches on `gws_oauth.configured` so both surfaces - # render the operator-provisioned shortcut when credentials are - # set, and the manual GCP walkthrough when they're not. - "connector_prompts": all_connector_prompts( - gws_oauth=get_gws_oauth_credentials(), - instance_admin_email=get_instance_admin_email(), - atlassian_base_url=get_atlassian_base_url(), - instance_brand=get_instance_brand(), - ), # Whether /home renders the "Step 3 — turn on auto-accept mode" # install-block. Operator can hide it via AGNES_HOME_SHOW_AUTOMODE=0 # for cautious rollouts; same content stays on /setup-advanced. diff --git a/app/web/templates/home_not_onboarded.html b/app/web/templates/home_not_onboarded.html index 034d1f1..64807e3 100644 --- a/app/web/templates/home_not_onboarded.html +++ b/app/web/templates/home_not_onboarded.html @@ -352,47 +352,6 @@ margin-bottom: 22px; } -.home-mock .connector-tiles { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 16px; - margin-bottom: 26px; -} -.home-mock .connector-tile { - background: white; - border: 1px solid var(--hp-border); - border-radius: 12px; - padding: 20px 22px; - display: flex; - flex-direction: column; -} -.home-mock .connector-tile .ico { - font-size: 24px; - margin-bottom: 10px; - line-height: 1; -} -.home-mock .connector-tile .ttl { - font-size: 15px; - font-weight: 600; - color: var(--hp-text-primary); - margin-bottom: 6px; -} -.home-mock .connector-tile .desc { - font-size: 13px; - color: var(--hp-text-secondary); - line-height: 1.55; - margin-bottom: 14px; - flex: 1; -} -.home-mock .connector-tile .connector-actions { - display: flex; - flex-direction: column; - gap: 8px; -} -.home-mock .connector-tile .connector-copy { - align-self: flex-start; -} - .home-mock .install-block { background: rgba(15, 23, 42, 0.55); border: 1px solid rgba(255, 255, 255, 0.10); @@ -492,118 +451,6 @@ text-decoration-color: #ffffff; } -.home-mock .automode-card { - margin: 22px 0; - background: white; - border: 1px solid var(--hp-border); - border-radius: 12px; - padding: 18px 22px; -} -.home-mock .automode-head { - display: flex; - gap: 14px; - align-items: flex-start; - margin-bottom: 14px; -} -.home-mock .automode-head .ico { - font-size: 22px; - flex-shrink: 0; - line-height: 1; -} -.home-mock .automode-head h3 { - font-size: 14px; - font-weight: 600; - margin-bottom: 4px; - color: var(--hp-text-primary); -} -.home-mock .automode-head p { - font-size: 13px; - color: var(--hp-text-secondary); - line-height: 1.55; - margin: 0; -} -.home-mock .automode-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 14px; -} -.home-mock .automode-step { - display: flex; - gap: 10px; - align-items: flex-start; - padding: 12px; - background: var(--hp-border-light); - border-radius: 8px; -} -.home-mock .automode-step .num { - width: 22px; height: 22px; - border-radius: 50%; - background: var(--hp-primary-light); - color: var(--hp-primary); - flex-shrink: 0; - display: flex; align-items: center; justify-content: center; - font-weight: 700; font-size: 11px; -} -.home-mock .automode-step .step-text { - flex: 1; - font-size: 12.5px; - line-height: 1.5; - color: var(--hp-text-secondary); -} -.home-mock .automode-step .step-text strong { - display: block; - color: var(--hp-text-primary); - margin-bottom: 4px; - font-size: 13px; -} -.home-mock .automode-step kbd { - background: white; - border: 1px solid var(--hp-border); - border-bottom-width: 2px; - border-radius: 4px; - padding: 1px 6px; - font-size: 11px; - font-family: var(--hp-font-mono); - color: var(--hp-text-primary); -} -.home-mock .automode-step code { - font-family: var(--hp-font-mono); - font-size: 11.5px; - background: white; - padding: 1px 5px; - border-radius: 3px; - color: var(--hp-text-primary); - border: 1px solid var(--hp-border); -} -.home-mock .automode-code { - background: #0F172A; - color: #FBBF24; - border-radius: 6px; - padding: 8px 10px; - margin-top: 6px; - font-family: var(--hp-font-mono); - font-size: 11.5px; - line-height: 1.5; - overflow-x: auto; - white-space: pre; -} -.home-mock .automode-foot { - margin-top: 12px; - padding-top: 10px; - border-top: 1px solid var(--hp-border-light); - font-size: 12px; - color: var(--hp-text-secondary); - line-height: 1.5; -} -.home-mock .automode-foot a { color: var(--hp-primary); text-decoration: underline; } -.home-mock .automode-foot code { - font-family: var(--hp-font-mono); - font-size: 11px; - background: var(--hp-border-light); - padding: 1px 4px; - border-radius: 3px; -} - .home-mock .section-label { font-size: 11px; font-weight: 600; @@ -648,8 +495,7 @@ } .home-mock .card-list .step-text { flex: 1; line-height: 1.55; } .home-mock .card-list .step-text strong { display: block; margin-bottom: 2px; } -.home-mock .card-list .step-text code, -.home-mock .card-mini-cmd code { +.home-mock .card-list .step-text code { font-family: var(--hp-font-mono); font-size: 11.5px; background: var(--hp-border-light); @@ -658,72 +504,6 @@ color: var(--hp-text-primary); } -.home-mock .card-mini-cmd { - margin-top: 6px; - padding: 8px 10px; - background: #0F172A; - color: #FBBF24; - border-radius: 6px; - font-family: var(--hp-font-mono); - font-size: 11.5px; - line-height: 1.5; - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 8px; -} -.home-mock .card-mini-cmd code { - background: transparent; - color: inherit; - padding: 0; - flex: 1; - white-space: pre-wrap; - word-break: break-word; -} -.home-mock .connector-head { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} -.home-mock .connector-head strong { - display: inline; - margin-bottom: 0; -} -.home-mock .connector-copy { - background: var(--hp-primary); - color: white; - border: none; - border-radius: 6px; - padding: 5px 12px; - font-size: 12px; - font-weight: 600; - cursor: pointer; - font-family: inherit; - flex-shrink: 0; -} -.home-mock .connector-copy:hover { background: var(--hp-primary-dark); } -.home-mock .connector-copy.copied { background: #047857; } -.home-mock details.connector-preview { - margin-top: 6px; -} -.home-mock details.connector-preview > summary { - cursor: pointer; - list-style: none; - font-size: 11.5px; - color: var(--hp-text-secondary); - padding: 2px 0; - user-select: none; -} -.home-mock details.connector-preview > summary::-webkit-details-marker { display: none; } -.home-mock details.connector-preview > summary::before { - content: "▸ "; - margin-right: 2px; -} -.home-mock details.connector-preview[open] > summary::before { content: "▾ "; } -.home-mock details.connector-preview > summary:hover { color: var(--hp-text-primary); } -.home-mock details.connector-preview .card-mini-cmd { margin-top: 6px; } - .home-mock .explore-list { list-style: none; padding: 0; margin: 0; } .home-mock .explore-list li + li { margin-top: 8px; } .home-mock .explore-item { @@ -1012,106 +792,6 @@ .home-mock .home-news-body p { margin: 0 0 8px; } .home-mock .home-news-body p:last-child { margin-bottom: 0; } -/* Setup-collapsible: each post-install section (Step 3 auto-mode, - Connect-your-tools) is wrapped in a
so it keyboard- - collapses without JS. Default state on /home: summary hidden, body - flat — visually identical to the pre-collapse layout. - - When the user clicks "Minimize setup view" in the hero, JS sets - `data-setup-minimized="1"` on `.home-mock` and removes the `open` - attribute on each
. The summary then appears as a slim - gray bar; the body collapses; clicking the bar re-opens that one - section. localStorage persists the minimize state per device. */ -.home-mock .setup-collapsible { margin-top: 22px; } -.home-mock .setup-collapsible > summary { - /* Default: summary is structural-only. The "flat" rendering is - handled by the inner blocks (.automode-card already provides its - own padding/border/background; the connect-your-tools section - starts with a .section-label-flat). */ - display: none; -} -.home-mock .setup-collapsible > summary::-webkit-details-marker { display: none; } - -/* Minimize ON: summary becomes a slim clickable bar; the inner body - inherits the existing block styling but tucks under the summary - when the
is closed. */ -.home-mock[data-setup-minimized="1"] .setup-collapsible { - border: 1px solid var(--hp-border); - border-radius: 12px; - background: white; - overflow: hidden; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible > summary { - list-style: none; - cursor: pointer; - padding: 14px 22px; - display: flex; - align-items: center; - gap: 12px; - font-size: 14px; - font-weight: 600; - color: var(--hp-text-primary); - background: #F9FAFB; - border-bottom: 1px solid transparent; - transition: background 120ms ease; - user-select: none; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible > summary:hover { - background: #F3F4F6; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ico { - font-size: 18px; - line-height: 1; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ttl { flex: 1; } -.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ttl small { - color: var(--hp-text-secondary); - font-weight: 400; - margin-left: 6px; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .chev { - font-size: 18px; - color: var(--hp-text-secondary); - transition: transform 160ms ease; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > summary { - border-bottom-color: var(--hp-border); - background: #F3F4F6; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > summary .chev { - transform: rotate(90deg); -} -/* Tighten the body padding so collapsed sections don't gain margin - when inside the white wrapper card. */ -.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .automode-card, -.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .connector-tiles { - margin: 18px 22px 22px; -} -.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .section-label-flat { - padding: 14px 22px 0; -} -/* When a section's
is closed in minimize mode, the body - already auto-hides via the browser's
behaviour — no extra - rule needed. */ - -/* Minimize toggle in the blue hero, only present when onboarded. */ -.home-mock .setup-minimize { - margin-top: 14px; - font-size: 13px; - color: rgba(255, 255, 255, 0.85); -} -.home-mock .setup-minimize button { - background: rgba(255, 255, 255, 0.10); - color: white; - border: 1px solid rgba(255, 255, 255, 0.25); - padding: 6px 14px; - border-radius: 6px; - font-size: 12px; - font-weight: 500; - cursor: pointer; -} -.home-mock .setup-minimize button:hover { background: rgba(255, 255, 255, 0.18); } - /* Callout, video-embed, news-hero, news-grid-*, news-cta — shared news content vocabulary now lives in app/web/static/style-custom.css under "News content vocabulary (shared)". Editing those rules in one place @@ -1172,84 +852,6 @@ color: white; } -/* P0-3 — connector card time badge ("~5 min · self-serve") and the - post-copy "now paste into Step 2" hint with arrow back. */ -.home-mock .connector-tile .ttl-row { - display: flex; align-items: center; justify-content: space-between; gap: 8px; - margin-bottom: 6px; -} -.home-mock .time-badge { - display: inline-flex; - align-items: center; - gap: 4px; - font-size: 11px; - font-weight: 600; - padding: 2px 8px; - border-radius: 999px; - background: var(--hp-primary-light); - color: var(--hp-primary-dark); - flex-shrink: 0; -} -.home-mock .time-badge.is-warn { - background: #FEF3C7; - color: #92400E; -} -.home-mock .copy-next-hint { - font-size: 12px; - color: var(--hp-primary-dark); - background: var(--hp-primary-light); - padding: 6px 10px; - border-radius: 6px; - margin-top: 6px; - display: none; - align-items: center; - gap: 6px; - line-height: 1.45; -} -.home-mock .copy-next-hint.is-visible { display: inline-flex; } -.home-mock .copy-next-hint code { - background: rgba(0, 0, 0, 0.06); - padding: 1px 5px; - border-radius: 3px; - font-family: var(--hp-font-mono); - font-size: 11px; -} - -/* P1-8 — GWS gating note + Email-admin button. Yellow background - matches the same friction-level used by other "admin help likely" - surfaces (advanced setup warnings). */ -.home-mock .gating-note { - font-size: 12px; - color: #92400E; - background: #FEF3C7; - border: 1px solid #FCD34D; - border-radius: 6px; - padding: 8px 10px; - margin-bottom: 10px; - line-height: 1.5; -} -.home-mock .email-admin { - display: inline-flex; - align-items: center; - gap: 6px; - background: white; - border: 1px solid var(--hp-border); - color: var(--hp-text-primary); - padding: 5px 12px; - border-radius: 6px; - font-size: 12px; - font-weight: 500; - text-decoration: none; - cursor: pointer; - align-self: flex-start; - margin-top: 6px; -} -.home-mock .email-admin:hover { - text-decoration: none; - border-color: var(--hp-primary); - color: var(--hp-primary-dark); -} - /* P1-6 — Auto-detect badge replaces the "Mark me as onboarded" button as the primary affordance. Pulse dot signals it's actively listening; the manual self-mark button stays as a fallback. */ @@ -1788,37 +1390,6 @@ Set-Location "$HOME\{{ workspace_dir }}" } document.querySelectorAll('.copy-btn[data-copy-target]').forEach(wireCopy); - // P0-3 + P2-12 — Connector copy buttons. Three things on click: - // 1) copy the prompt (same textContent trick so closed
- // still copies); - // 2) flip the button to "✓ Copied" + disabled for 8 s so the user - // stops mashing it while figuring out where to paste; - // 3) reveal a paste hint pointing the user at Claude Code. - document.querySelectorAll('.connector-copy[data-copy-target]').forEach(function (btn) { - btn.addEventListener('click', function () { - var src = document.getElementById(btn.getAttribute('data-copy-target')); - if (!src) return; - var raw = src.textContent || ''; - var connector = btn.getAttribute('data-connector') || ''; - var hint = connector - ? document.querySelector('.copy-next-hint[data-hint-for="' + connector + '"]') - : null; - navigator.clipboard.writeText(raw).then(function () { - var orig = btn.textContent; - btn.classList.add('copied'); - btn.textContent = '✓ Copied'; - btn.disabled = true; - if (hint) hint.classList.add('is-visible'); - setTimeout(function () { - btn.classList.remove('copied'); - btn.textContent = orig; - btn.disabled = false; - if (hint) hint.classList.remove('is-visible'); - }, 8000); - }).catch(function () { btn.textContent = 'Copy failed'; }); - }); - }); - // OS tab switching for Step 1. Flips both the command panel AND the // P0-1 terminal-howto body so the howto matches the active OS. document.querySelectorAll('.os-tab[data-os-tab]').forEach(function (tab) { @@ -1948,48 +1519,6 @@ Set-Location "$HOME\{{ workspace_dir }}" }); } - // ── Minimize-setup toggle ──────────────────────────────────────── - // Default OFF: sections render flat (no visible). - // ON: data-setup-minimized="1" on .home-mock activates the slim - // gray summary bars;
open/close handles per-section - // expansion. Per-device via localStorage; survives reloads but - // resets on a new machine — which is correct (the user might - // want the full reference there). - var KEY = 'agnes_home_setup_minimized'; - var mockEl = document.querySelector('.home-mock'); - var minToggle = document.getElementById('setupMinimizeToggle'); - var collapsibles = document.querySelectorAll('.setup-collapsible'); - - function applyMinimize(on) { - if (!mockEl) return; - if (on) { - mockEl.setAttribute('data-setup-minimized', '1'); - collapsibles.forEach(function (d) { d.removeAttribute('open'); }); - if (minToggle) { - minToggle.textContent = 'Show full setup view'; - minToggle.setAttribute('aria-pressed', 'true'); - } - } else { - mockEl.removeAttribute('data-setup-minimized'); - collapsibles.forEach(function (d) { d.setAttribute('open', ''); }); - if (minToggle) { - minToggle.textContent = 'Minimize setup view'; - minToggle.setAttribute('aria-pressed', 'false'); - } - } - } - - // Initial state — only when the toggle exists (= onboarded view). - if (minToggle) { - try { applyMinimize(localStorage.getItem(KEY) === '1'); } - catch (e) { /* ignore localStorage failures (private mode) */ } - minToggle.addEventListener('click', function () { - var nowOn = mockEl.getAttribute('data-setup-minimized') !== '1'; - try { localStorage.setItem(KEY, nowOn ? '1' : '0'); } catch (e) {} - applyMinimize(nowOn); - }); - } - // ── Generic dismiss-card handler ───────────────────────────────── // Any `