release: 0.54.14 — changelog repair + post-#305 dead-code sweep (#309)
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.
This commit is contained in:
parent
cb13f80241
commit
e290baa31b
4 changed files with 98 additions and 538 deletions
135
CHANGELOG.md
135
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
|
||||
`"<plugin>@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 `<details data-section="connectors">` 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 `<details data-section>`
|
||||
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
|
||||
`"<plugin>@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.<timestamp>` 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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 <details open> 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 <details>. 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 <details> 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 <details> is closed in minimize mode, the body
|
||||
already auto-hides via the browser's <details> 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 }}"</span>
|
|||
}
|
||||
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 <details>
|
||||
// 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 }}"</span>
|
|||
});
|
||||
}
|
||||
|
||||
// ── Minimize-setup toggle ────────────────────────────────────────
|
||||
// Default OFF: sections render flat (no <summary> visible).
|
||||
// ON: data-setup-minimized="1" on .home-mock activates the slim
|
||||
// gray summary bars; <details> 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 `<button class="home-card-close" data-dismiss-key="...">`
|
||||
// inside a `<section>` becomes dismissible: clicking sets the
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "agnes-the-ai-analyst"
|
||||
version = "0.54.13"
|
||||
version = "0.54.14"
|
||||
description = "Agnes — AI Data Analyst platform for AI analytical systems"
|
||||
requires-python = ">=3.11,<3.14"
|
||||
license = "MIT"
|
||||
|
|
|
|||
Loading…
Reference in a new issue