Repository navigation
Refactor/singbox config layout - #12
Merged
Merged
Conversation
added 10 commits
September 26, 2026 10:57
Eleven packages declared a name different from their directory (singbox -> service, outbounds/rules -> noderules, traffic -> trafficflow, installation -> installer, identity -> user, ...). Each is renamed to its directory. Importers were rewritten qualifier-by-qualifier; where the new name would shadow a local identifier the old name is kept as an explicit import alias instead. No behaviour change.
- Delete config/ruleset_refs.go: the typed rule-set cascade had no callers once deletes moved to the raw-JSON walk in configuration. Its RuleSetRef and RefScope/RefAction types move there, and its test cases are ported to the raw implementation so the behaviour stays pinned. - Delete the typed write path on config.Manager (GetConfig, SaveConfig, UpdateConfig, ValidateConfig, GetBackupConfig, GetVersion). Every save already goes through SaveDocument/UpdateConfigSection, which fail closed. - Replace the two loose parseVersion copies (singbox, installation) with config.DisplayCoreVersion, built on the same ParseCoreVersion that drives capability gating.
config held selector/urltest group building, group-reference pruning and node-tag minting even though only outbounds and subscription used them. They move to two leaf packages under outbounds, so both outbounds and outbounds/rules can import them without a cycle: - outbounds/nodegroup: BuildGroupOutbounds, PruneGroupReferences, the endpoint/opt-in classification and the Filter/Group specs - outbounds/nodetag: fingerprinted tag minting and endpoint keys Manager.UpdateOutbounds becomes outbounds.addOutbounds, its only caller's package. config.NewManagerWithCore lets other packages run the real validate-and-rename path against a fake core, which the first outbounds tests use: legacy-tag skips, no-op adds that write nothing, and renames and deletes carried into selector/urltest members.
Every config package serves sing-box, so they now live beside the process
controller instead of as unrelated top-level packages:
singbox/ process controller (unchanged)
singbox/core the binary: version, check, capabilities
singbox/config document store (config.Manager)
singbox/config/history version history
singbox/config/sections dns/route/inbound/experimental editors
(was app/pkg/configuration)
singbox/config/outbounds outbound editor + nodegroup/nodetag/rules
(was app/pkg/outbounds)
core is split out of config so the controller and the installer can read
the core version without the document store, and so there is one parser.
The store keeps package name config, so config.Manager reads the same
everywhere; only import paths change.
app/architecture/layering_test.go pins the direction: core is a leaf, the
store does not know its editors, sections and outbounds never import each
other, and nodegroup/nodetag stay leaves. The go:generate path moved with
the registry; regenerated inventories differ only in their header path.
The config and version-history handlers were the one place the HTTP layer called config.Manager directly, each classifying errors by hand. They now go through config.Service, which owns the id rules and maps store failures onto fault kinds, so these routes share respondOperationError with every other module. Response codes and messages are unchanged and pinned by a handler test. app/architecture now bans the Manager's document and history methods in handlers, and CLAUDE.md documents the new singbox/ tree and the write paths that replace the removed typed UpdateConfig.
clashapi is the client for the running sing-box's own API, the process-side counterpart of singbox/core (the binary). It moves from the generic integrations/ folder, which held nothing else, to singbox/clashapi. The HTTP-adapter ban that matched /integrations/ now names the new path, and the layering test makes clashapi a leaf and keeps the config packages from depending on a running sing-box.
SystemType and DetectSystemType lived in the sing-box controller package, but they classify the HOST: the controller picks its init backend from them, the installer picks opkg vs the install script, and the HTTP layer picks the login default and navigation layout. They now sit in platform/sysinfo beside the Distribution display name. The installer's only reason to import the controller was this detection, so it now depends on singbox/config and singbox/core alone. The HTTP handler keeps the value as the plain string it serialises, so the routes still import no platform package.
Every file in it manages a sing-box artifact: the binary (install script or opkg), the Clash dashboard it serves as external_ui, the first config.json, and the setup state recording which of those are done. It now sits beside config at singbox/install, with state and state/repo below it. With host detection moved to platform/sysinfo in the previous commit, the package imports only singbox/config and singbox/core; the layering test now forbids it the controller and clashapi. The Phase 0 import alias `installer` is gone from the two handlers that no longer need it.
The Add/Edit DNS Rule dialog had no control for query_type, so a rule matching on record types could only be written by hand. It is now a multi-select of the common types (A, AAAA, HTTPS, SVCB, ...), rendered apart from the rule-set/domain either-or because sing-box ANDs it with every other condition. sing-box decodes a DNSQueryType from a number or a known NAME and rejects a numeric string, so utils/dnsQueryType converts at the boundary: numbers become strings for the select and numeric strings go back out as numbers. A value outside the common list stays visible as a selected option rather than vanishing on open and being dropped on save. No version gate: the field exists in the pinned 1.12.12 option struct, the minimum supported core.
PrimeVue's Dialog defaults draggable to true and starts a drag on any mousedown in the header, so selecting the title to copy it moved the whole dialog instead. The volt wrapper now declares draggable itself with a false default; a caller can still opt in with :draggable="true".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.