v1.0.3 -- "宇宙是蚂蚁的梦。"
-
chore(release): bump version to 1.0.3
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
feat(profiles): give each tab its own action button
-
The Profiles scaffold showed one Add Profile button for all three tabs,
-
while the node and chain actions sat inline above their lists. The
-
button that matters depends on the tab you are looking at.
-
Drive the floating action button from the tab index: Add Profile on
-
Profiles, Create node and Import node on Nodes, Create chain on Chains.
-
The inline buttons in the node toolbar and above the chain list are gone
-
now that the actions live in the scaffold; the empty states keep theirs
-
as a call to action.
-
The two node buttons sit at opposite edges, which the end-aligned slot
-
cannot express, so CommonScaffold gained a floatingActionButtonLocation
-
and that tab uses centerFloat with the edge inset added back.
-
To reach the actions from the scaffold, the node import/create handlers
-
and the chain create handler become top-level functions in their own
-
files; the views delegate to them.
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
feat(nodes): import nodes without a preview step
-
Removing only the overwrite-or-copy radios left the preview dialog in
-
place, so importing still interrupted the user to confirm a list they
-
did not ask to review. Importing a link means "add this": parse it, add
-
what is valid, and report what is not.
-
Drop the preview entirely from both import paths. NodeLibraryService
-
already skips drafts that fail to parse and returns their issues, so the
-
Nodes tab now surfaces those issues instead of showing them in a list
-
nobody needed to approve. Binding follows the caller as before: imports
-
bind to the current profile when there is one.
-
Delete NodeImportPreview, NodeImportSelection and their test, along with
-
the importPreview and bindCurrentProfile messages that only that dialog
-
used. _previewAndCommitNodes becomes _commitNodes, since it no longer
-
previews anything.
-
Verified on an Android emulator: a node deep link and the Nodes tab
-
import both create the node with no dialog, and importing the same link
-
twice yields two copies.
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
feat(nodes): always add on import instead of asking about duplicates
-
The import preview asked the user to choose between updating the
-
existing node and creating a copy. The choice is not worth a prompt:
-
importing a link means "add this", and re-importing the same link should
-
simply yield another copy.
-
Drop the radio group and commit imports with createCopy, so the preview
-
only asks what it still needs, which drafts to keep and whether to bind
-
them to the current profile.
-
Clean up what the choice left behind:
-
- NodeImportSelection.createCopy, now that nothing reads it.
-
- The createCopy parameter on importNodeText and _previewAndCommitNodes,
-
which no caller ever passed.
-
- The updateExisting message, whose only reference was the removed radio.
-
NodeLibraryService.commit keeps its createCopy parameter: the node menu
-
still duplicates a node with it, and manual creation still dedupes by
-
fingerprint without it.
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
fix(android): keep warm-start deep links out of Flutter routing
-
Deep links are handled by app_links, but the Flutter engine's own deep
-
link handling is on by default and pushes the incoming URI into the
-
navigation system. This app uses a plain MaterialApp with no route
-
generator, so a link delivered to an already running instance raised
-
"Could not find a generator for route" and never reached LinkManager.
-
Cold start worked only because getInitialLink reads the intent
-
directly. Warm start is the common case here, since the app is meant to
-
stay running in the background while a subscription link is opened from
-
a browser or chat app.
-
Set flutter_deeplinking_enabled to false so the intent reaches
-
app_links in both cases.
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
fix(nodes): treat every http(s) URI as a subscription
-
isHttpProxyUri classified any http(s) URI with an explicit port as an
-
HTTP proxy node, so a subscription link served on a non-default port
-
was imported as a node instead of creating a profile. Self-hosted
-
panels commonly use ports such as 8443 or 2096, and the
-
avalon://install-config deep link routes through the same path, so its
-
explicit intent was overridden by the heuristic.
-
http and https are no longer node schemes, matching what the deep link
-
dispatcher and the Android intent filters already assumed. Drop
-
HttpCodec, its https alias and the port heuristic, and let importText
-
treat any http(s) URI as a subscription URL.
-
Raw Mihomo configs carrying
type: httpproxies keep working; only the -
URI codec is gone.
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
perf(telemetry): gate UI telemetry on a unified activity state
-
Traffic sampling ran on a fixed 1s global timer that only stopped when
-
the proxy stopped, so a hidden window still paid for Dart scheduling,
-
two IPC round trips and provider updates every second.
-
Introduce a process-wide AppActivityState fed by the Flutter lifecycle,
-
window visibility and window focus, and drive telemetry from it:
-
- SetupAction picks 1s, 5s or no sampling from the current activity,
-
the dashboard traffic widgets and the tray title need, resamples
-
immediately on resume, and skips a tick while a request is in flight.
-
- The tray speed title is macOS-only, so its need is platform-gated;
-
otherwise showTrayTitle (default true) kept background sampling alive
-
for a consumer that does not exist off macOS.
-
- Pages and the app root wrap their subtree in TickerMode so animations
-
stop when the page or the window is inactive.
-
- NetworkSpeed and TrafficUsage drop their provider subscription while
-
inactive; Logs and Requests buffer through ActiveSnapshotMixin and
-
commit one snapshot once page and window are both active again.
-
- Tray titles dedupe on the formatted string, and getTraffic /
-
getTotalTraffic bypass the debug RPC timing logs.
-
Frame pausing now distinguishes an on-screen window from a hidden one:
-
blur only gates telemetry and tickers, while hide and minimize pause
-
frames after 300ms instead of 5s. Losing focus must not stop frames, as
-
an unfocused window is still scrollable and would appear frozen.
-
Verified on an Android emulator: 1 tick/s in the foreground, zero ticks
-
across 25s backgrounded, and an immediate resample on resume.
-
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
-
Claude-Session: https://claude.ai/code/session_01THm54YvuV1sjPqEMGFrgxq
-
fix(ui): show chain names and align node actions
Download based on your OS: