Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .trellis/spec/backend/external-agent-catalog-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ Parser drift against this table rejects the whole catalog.

### Static catalog

- Directory descriptions state supported capabilities only, without a list of
unsupported features or runtime uncertainty. Keep exact capability modes and
action-time errors/unknown states unchanged; positive summary prose does not
grant new authority. TRAE's model handoff may be described positively with
its vendor-owned location.

- The catalog is deterministic and performs no filesystem, process, network,
registry, database, or credential read.
- IDs, order, display names, variant IDs, official links, capability order and
Expand Down Expand Up @@ -186,6 +192,8 @@ Required assertion points:

- exact contract version, product order, capability order, link IDs and closed
enums in Rust and `src/shared/features/agents.ts`;
- every directory description remains positive supported-capability prose while
the exact capability modes/reasons stay unchanged and independently asserted;
- `EXPECTED_AGENT_LINK_IDS` matches the native v5 table; Claude Desktop and
Claude CLI+Desktop payloads fail closed;
- unknown/excess fields, duplicate IDs and legacy/future versions fail closed;
Expand Down
96 changes: 96 additions & 0 deletions .trellis/spec/backend/first-use-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Device-local First-use Guide

## 1. Scope / Trigger

Read before changing first-install eligibility, guide persistence or its Tauri
commands. `settings/first_use_guide.rs` owns the state; `lib.rs` supplies startup
data-directory evidence. [Renderer First-use Guide](../frontend/first-use-guide.md)
owns presentation and recommendations. This is not software installation,
authentication, model configuration, telemetry or a database migration.

## 2. Signatures

```text
settings.json: firstUseGuideState?: "pending" | "dismissed"
settings.json: firstRunNoticeConfirmed?: boolean # legacy compatibility
get_first_use_guide_state() -> "pending" | "dismissed"
dismiss_first_use_guide() -> Result<"dismissed", String>
```

Commands accept no paths, settings snapshots, software IDs or purpose choices.
Register both in `generate_handler!` and the active application permission set.
The Tauri SettingsPort parses unknown responses; a `pending` dismissal response
is an error rather than successful completion.

## 3. Contracts

### Admission and restart authority

- Initialize pending before database creation/seeding, only when the database,
legacy `config.json` and device `settings.json` are confirmed absent. An
existence-check error is not absence. A present, malformed or unreadable
settings file is an existing/unknown installation and must not be overwritten
just to initialize this guide.
- No marker on an existing installation means dismissed. Do not infer first
install from an empty providers table, a missing renderer localStorage key,
application version or the absence of detected third-party software.
- Existing pending survives restart; dismissed and legacy
`firstRunNoticeConfirmed: true` suppress the guide. Closing the app without
finishing or skipping does not manufacture user acknowledgement.
- The device file, not the synced database or renderer cache, is the restart
authority. Removing all local application data creates a new installation
context; replacing the app binary while retaining data does not.

### Mutation authority

- Dismissal uses the existing settings write lock and persistence owner to
merge only `firstUseGuideState: dismissed` and
`firstRunNoticeConfirmed: true`. Persist before changing the in-memory value.
- Both fields are native-owned for this workflow. Ordinary `save_settings`
preserves their latest locked values exactly: a stale payload cannot reopen
dismissed state, and an arbitrary payload cannot dismiss pending state through
either the current marker or the legacy acknowledgement. Returning those
fields in a compatibility settings snapshot does not grant write authority.
- `dismiss_first_use_guide` is the only Renderer-reachable transition from
pending to dismissed. It is idempotent for an already dismissed installation.
Purpose choice is component-local and is never persisted or transmitted.

## 4. Validation & Error Matrix

| Condition | Result |
| ------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Confirmed new local data, no acknowledgement | Persist pending before DB initialization. |
| Existing DB, JSON or settings and no marker | Return dismissed without onboarding initialization writes. |
| Settings exists but is malformed/unreadable, or any existence check fails | Treat as existing/unknown; do not create pending. |
| Pending with DB now present | Continue pending. |
| Dismissed or legacy confirmed | Do not reopen. |
| Initialization persistence failure | Log safely; do not claim pending was saved. |
| Dismissal persistence failure | Return failure and retain prior in-memory state. |
| Ordinary settings payload changes either first-use field | Ignore both incoming values and preserve the latest locked pair. |
| Unknown wire state or pending dismissal acknowledgement | Reject at renderer adapter. |

## 5. Good / Base / Bad Cases

Good: a completed guide remains dismissed after a settings panel saves an old
snapshot, while a pending guide cannot be acknowledged through that same generic
save path. Base: an interrupted first launch resumes its pending guide. Bad:
checking providers after built-in providers were seeded or submitting the
entire renderer settings object merely to dismiss onboarding.

## 6. Tests Required

`settings/first_use_guide.rs` tests cover the all-absence admission matrix,
existing markers, legacy acknowledgement, closed serialization and pending
restart. The commands/settings merge test protects both directions: stale input
cannot reopen completion or acknowledge pending state. Renderer port and ACL
tests cover exact no-argument calls, response rejection and
registration/permission closure. Run Rust format/check/Clippy/tests and Renderer
type/lint/unit gates. Browser persistence fixtures are mock evidence, not
fresh-install HIL evidence.

## 7. Wrong vs Correct

Wrong: `save_settings({ ...cachedSettings, firstRunNoticeConfirmed: true })` or
trusting an incoming `firstUseGuideState`. Correct: ordinary settings saves copy
both fields from the latest locked state; `dismiss_first_use_guide()` alone
merges the completed pair and acknowledges only after persistence.
3 changes: 3 additions & 0 deletions .trellis/spec/backend/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ secret handling, native source checks, and residual-risk reporting.

## Product, configuration, and runtime security

[Device-local First-use Guide](./first-use-guide.md) owns new-install eligibility,
settings persistence, narrow commands and protection against stale settings saves.

[Agent Health Observation](./health.md) owns the on-demand local status
snapshot and its read-only installation/configuration/auth/proxy evidence.

Expand Down
4 changes: 3 additions & 1 deletion .trellis/spec/frontend/agent-directory.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Primary owners:
Native authority is split between
[Agent Catalog and Runtime](../backend/external-agent-catalog-runtime.md) and
[Agent Lifecycle](../backend/external-agent-lifecycle.md). Auth UI has its own
owner: [Renderer Agent Auth](./agent-auth.md).
owner: [Renderer Agent Auth](./agent-auth.md). First-install eligibility and the
optional recommendation page belong to [First-use Guide](./first-use-guide.md).
The ordinary directory scan waits while that guide is active.

## 2. Signatures

Expand Down
132 changes: 132 additions & 0 deletions .trellis/spec/frontend/first-use-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# First-use Software Recommendations

## 1. Scope / Trigger

Read before changing first-use presentation on `/agents`. `FirstUseGuide.tsx`
owns the two-step UI; `firstUseRecommendations.ts` owns the route-local purpose
association. [Native First-use State](../backend/first-use-guide.md) owns device
eligibility and persistence. [Agent Directory](./agent-directory.md) still owns
catalog, installation, configuration and software order.

## 2. Signatures

```ts
type GuidePurpose = "office" | "coding" | "both";
type FirstUseGuideState = "pending" | "dismissed";
SettingsPort.getFirstUseGuideState(): Promise<FirstUseGuideState>;
SettingsPort.dismissFirstUseGuide(): Promise<"dismissed">;
```

Use `featureKeys.firstUseGuide` through the shared query owner. The native
adapter parses unknown responses; browser fallback returns dismissed and
rejects native-only dismissal instead of pretending to save.

## 3. Contracts

### Route and startup

- Only the directory branch may show onboarding. A valid explicit `target`
remains authoritative and disables the first-use query. Query activity follows
persistent route visibility.
- Wait for catalog and guide-state settlement before presenting the directory
or guide and acknowledging frontend-ready. Do not use RAF/document visibility
for native startup readiness. A failed guide read opens the ordinary directory,
not an invented fresh-install state.
- A catalog error, empty catalog or target/catalog mismatch keeps the existing
directory error/empty/recovery surface and its ready acknowledgement. Do not
mount an incomplete guide or write dismissal without a valid parsed catalog.
- Lazy-load the one-time guide and its CSS only for a pending user. The committed
guide component owns frontend-ready while its chunk is loading; a Suspense
placeholder must not reveal the native window. Catalog error/empty states keep
their own ready acknowledgement instead of waiting for an unmounted guide.
Keep the existing initial-JavaScript budget; do not raise it to admit onboarding.
Audit the static dependency closure as well as page chunks: a hook first used
in a lazy page can still grow a bootstrap-shared vendor chunk. Keep this narrow
write consistent with the existing guarded local-operation pattern.

### Recommendation projection

- The question is one sentence, with office, coding and combined-use options.
Both steps expose skip. Selection shows a small set of recommendations, with
back/reselect and a full-directory action; it is not an installation wizard.
- Office recommends QoderWork CN, TRAE Work CN and WorkBuddy; coding recommends
Grok Build, Codex, Claude Code and OpenCode; combined use recommends WorkBuddy
and Codex.
These are purpose associations, not capability, platform or quality rankings.
Intersect IDs with the parsed catalog and preserve its names/order. Do not
create a fallback catalog or infer installation/action permissions.
For the current seven products, the office/coding union covers the complete
catalog, with a concise purpose description for each. The purpose-description
map is exhaustive over the closed `AgentCatalogId`; never fall back to a
generic catalog description when a reason is missing. Cross-check identities
against `AGENT_CATALOG_IDS`; do not silently omit a product by testing only a
copied shortlist. A future new identity must receive an explicit description,
while any deliberate exclusion from both single-purpose sets requires a
recorded product rationale. Combined use remains a curated entry point, not
the full catalog union.
- Purpose is component-local. Choosing it performs no native write, auth,
install, model change or telemetry.

### Completion and lifecycle

- Directory scanning starts only after the first-use check settles with no guide
or after dismissal succeeds. Never start it behind the guide.
- Completion and skip use the same narrow native dismissal. Keep the current
step on failure with a safe retry message; never display raw native errors.
A synchronous admission guard and disabled controls prevent duplicate writes.
- Cache only successful persisted dismissal. Hidden/unmounted completion may
update the shared state but must not steal focus, reopen portals or scan.
Focus the guide heading on step changes and the directory heading on visible
completion. Reuse Button/PressableButton, brand assets and semantic CSS tokens.

## 4. Validation & Error Matrix

| Condition | UI behavior |
| ----------------------------------------------------- | ------------------------------------------------------------------- |
| Pending and valid catalog on directory | Show purpose question, not a directory flash. |
| Dismissed / old installation | Ordinary directory. |
| Explicit software target | Existing configuration view, no guide interception. |
| Guide read fails | Ordinary directory; no acknowledgement write. |
| Catalog fails, is empty, or cannot resolve the target | Existing catalog error/empty/recovery UI; no guide acknowledgement. |
| Save pending | Keep guide; disable duplicate actions and choices. |
| Save fails | Keep current recommendations; allow retry. |
| Save succeeds | Full directory; no repeat with a fresh query client. |
| Route hidden while save finishes | Update cache without focus or scan work. |

## 5. Good / Base / Bad Cases

Good: recommend current catalog names, then let the user browse all software.
Base: restart an unfinished guide at the purpose question. Bad: turn a purpose
selection into an automatic installation, persist a marketing profile or force
existing installations through onboarding after an upgrade.

## 6. Tests Required

`pages/agents/Page.test.tsx` covers all three sets, reselection, both skip paths,
completion, new query-client restart, delayed/failed persistence, duplicate
clicks, unknown startup reads, target links and hidden completion. Native-port
tests reject unknown states and pending write acknowledgements.
The office/coding coverage assertion compares recommendation identities with
the shared catalog IDs, independently of per-choice expected names. Typecheck
must reject a new closed catalog identity without an explicit purpose reason;
tests also reject using the generic entry description as that reason. Keep Grok
Build's coding reason, supplied catalog order and current-name regression.
`browser/first-use-guide.spec.ts` covers keyboard focus, both themes,
large-small-large viewport changes, real click reachability, persistence and
positive catalog copy in Chromium/WebKit. Run the existing directory/browser
regressions and production boot gate. WebKit keyboard tests use its Option-Tab
all-controls navigation, without changing the host keyboard-access setting.
The four-item coding result must keep recommendations and completion/skip
controls reachable at the smallest supported viewport. Browser fixtures do not
prove native first-install or Windows/macOS installer behavior.
The production navigation smoke test also verifies that a fresh user loads the
guide chunk and a post-skip reload does not request it.

## 7. Wrong vs Correct

Wrong: `if (!localStorage.getItem("welcome")) showGuide()`, using
`reason ?? entry.description`, or hiding unsupported actions by rewriting their
runtime status. Correct: native first-use state owns eligibility; every closed
catalog identity has an explicit purpose reason; only catalog summary prose is
positive-only, while actual operation errors, unknown states and security
confirmations stay visible.
1 change: 1 addition & 0 deletions .trellis/spec/frontend/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ focused feature owner. Apply [Component Guidelines](./component-guidelines.md),
| [Window Shell](./window-shell.md) | Chrome, native overlay boundary, selection and shared interaction. |
| [Change Plan Workspaces](./change-plan-workspaces.md) | Preview/apply, source switching, job observation and reconciliation. |
| [Agent Directory](./agent-directory.md) | Catalog, scan/readiness, cards, installation and capabilities. |
| [First-use Guide](./first-use-guide.md) | Skippable purpose recommendations, native eligibility and completion. |
| [Agent Health](./health.md) | Local check snapshots, stale facts, serial refresh and existing repair routes. |
| [External Agent Auth](./agent-auth.md) | Native auth observations, session ownership and safe handoff. |
| [Managed Auth](./managed-auth.md) | Accounts/connections/request sources, login and impact confirmation. |
Expand Down
8 changes: 7 additions & 1 deletion .trellis/spec/frontend/user-facing-copy.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ not user copy.
- Windows vendor-wizard success copy states that the installer opened and the
user should finish it, then refresh. It must not say the product is installed.
- OpenCode Windows x64 may be offered as a current-user official installer.
ARM64 remains unavailable. Catalog description states Skills/MCP/Hooks
ARM64 remains unavailable. Catalog description states Skills/model/MCP support
only; do not add 「本机识别和启动暂无法确认」. Claude Code now uses its
CLI-only lifecycle and must not promise Claude Desktop support. Destination labels may use the
display name and must not be treated as the scanned folder
Expand Down Expand Up @@ -126,6 +126,12 @@ Examples:

### Concise secondary surfaces

Software-directory summaries describe supported capabilities, not lists of
unsupported features. Keep capability matrices and real failure/unknown/safety
messages at their operation points. First-use recommendations use one question,
three purpose choices and an explicit skip action; see
[First-use Guide](./first-use-guide.md).

The object name, meaningful state and actions are the default hierarchy across
all eight routes and their details/dialogs. A heading does not require a
subtitle. Add supporting text only for a non-obvious choice, consequence,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{"file":".trellis/spec/frontend/agent-directory.md","reason":"原生目录和浏览器回归"}
{"file":".trellis/spec/frontend/quality-guidelines.md","reason":"类型、测试与真实证据边界"}
{"file":".trellis/spec/backend/modular-boundaries.md","reason":"窄命令注册、权限和 owner 复用"}
{"file":".trellis/spec/frontend/first-use-guide.md","reason":"两步引导、推荐、键盘与重启回归"}
{"file":".trellis/spec/backend/first-use-guide.md","reason":"兼容旧安装和完成状态防覆盖"}
Loading