- Deployments are on internal networks with self-signed UME certificates:
installers write NETX_UME_VERIFY_TLS=false and
NETX_ALLOW_INSECURE_DEFAULTS=1 when absent (Linux also on update), so
binding 0.0.0.0 no longer stops NetX at the startup security check.
Admin password and JWT secret stay unique per install.
- Linux: after install, check app_user to report whether the generated
initial password applies or the admin already exists (reused external
DB); new 'netxctl admin-password'.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Installing under /root left systemd failing with 203/EXEC and empty logs.
The installer now checks that the service user can enter the program and
data dirs; blocked parents are granted traverse-only access (setfacl
u:netx:x, else chmod o+x) with --grant-access or after asking, otherwise
it stops with the exact command. Start failures show the supervisor log
or journalctl when api.log is empty. README: /root installs and UME with
self-signed certificates (NETX_ALLOW_INSECURE_DEFAULTS).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An entry like "all" made every port probe fail and the installer said
"port in use" forever. Aliases (all/*, local) are normalized, other
values must be an IPv4 address of this host, and port-free now tells a
busy port (exit 1) from a bad address (exit 3). Same check for set-bind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Forgejo can hand out /attachments/<uuid> links; the release API's own
names stay authoritative. (The v0.4.19 updater already works against
releases/latest, which returns named download URLs.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- packaging/linux: netx-<ver>-linux-x86_64.tar.gz with bundled Python 3.12,
PostgreSQL 16 and web/dist (glibc >= 2.17). install.sh (install/update/
reinstall), netxctl (start/stop/status/logs, set-port, set-bind,
set-pg-port, reconfigure-db, check-update/update/auto-update, backup,
uninstall), systemd units, nohup fallback without systemd. Privilege
drop, detaching and tar go through the bundled Python, so bare images
without su/runuser/setsid/tar work.
- Updates: same GitHub/Forgejo/manifest sources as Windows, sha256
verified, pre-update pg_dump, automatic rollback when the new version
does not come up.
- Non-loopback bind: generated bootstrap admin password and
NETX_UME_VERIFY_TLS=true, as security_bootstrap requires.
- Build in manylinux2014 + check_bundle.sh (GLIBC <= 2.17, no missing
libs); release-linux.yml builds on v* tags and smoke-tests offline on
CentOS 7, Rocky 9, Ubuntu 18.04/24.04, Debian 12, openSUSE Leap 15 and
openEuler 22.03 before attaching to the release.
- Windows: Setup DB page gets a bundled PG port field and
/BundledPgPort=; set_pg_port.ps1 + tray "Built-in database port";
reconfigure keeps the configured port; postgresql.conf is written
without a BOM (PS 5.1 Set-Content -Encoding utf8 broke postgres).
- Forgejo/GitHub publish scripts include the Linux package.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- queryNmsAlarms no longer silently clamps page to 2; add is_cleared.
- Bad integer args return invalid_argument tool errors instead of JSON-RPC crashes.
- Nested {"ok": true, "data": {"ok": false}} results are flagged isError.
- stdio: answer ping, never respond to notifications, version from metadata.
- getNmsNe resolves exact host_name/IP; severity lowercased.
- Outputs use nms_ne_id/source=nms; drop ME{uuid} names, echoed field lists, idle hop_* fields.
- Fabric paths: parallel links count as one hop (edges[].parallel_links).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The GitHub runner's toolcache keeps python-3.12.x-amd64.exe (~25MB) and
_test*.pyd next to python.exe; exclude them so CI Setups match local
ones (0.4.18 CI build was 70MB vs 44MB local).
- publish_forgejo_release.ps1: curl --noproxy for the Forgejo host; a
desktop HTTP(S)_PROXY returned 502 for the LAN address.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Start: WinSW's NetX.out.log/err.log in data\runtime are the same files as
start_netx.ps1's netx.out.log (case-insensitive) and stay open, so NetX
could not truncate its log and every start failed. WinSW logs now go to
data\runtime\service.
- Stop: nothing told the service_run.ps1 supervisor to exit, so it kept
restarting NetX and WinSW waited forever. stop_netx_app.ps1 writes the
service.stop flag (-KeepSupervisor for the supervisor's own restarts),
service_run checks it every second, and runtime_ctl / service_lifecycle
write it before stopping the service.
- WinSW launched powershell.exe as stop hook never reached the script
(stuck on inherited std handles); run it via cmd with NUL stdin and output
to data\runtime\service\stopexec.log. stop_netx_app.ps1 keeps a
timestamped trace there.
Offline Windows Sandbox: service install -> healthy in 28s, stop in 20s.
Existing service installs need "install service" re-run to pick this up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows PowerShell 5.1 Start-Process -Wait (and `& exe` with captured
output) waits for every descendant / until the stdout pipe closes. The
postgres and NetX processes a start leaves running made runtime_ctl.ps1
never return: tray stuck on "Starting", Start Menu "Start NetX" never
opened the UI. Start-NetxPowerShell -Wait, the UAC relaunch and the Setup
wait in check_update now wait for the process itself (WaitForExit).
Service mode in runtime_ctl: start via sc.exe without blocking on
SERVICE_RUNNING; stop writes the supervisor stop flag, polls up to 120s,
then kills the WinSW tree as a last resort.
Verified in an offline Windows Sandbox (no VC++ redist, no Python).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The EDB binaries link vcruntime140 (and msvcp140 via ICU), which a clean
Windows install lacks, so the built-in DB and the wizard's external-DB
connection test (psql) failed on fresh/offline PCs without the VC++
2015-2022 redistributable. Copy vcruntime140(_1)/msvcp140(_1,_2) into
postgres\pgsql\bin at build time and extract vcruntime140 with psql.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings -> Update source writes NETX_UPDATE_SOURCES to ProgramData .env:
empty keeps the default (GitHub first, git.avelo.top mirror as fallback),
"forgejo" pins updates to git.avelo.top.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pandas + numpy were ~60MB of the shipped venv for three call sites (alarm
Excel import, managed-NE import, import template). netx_api/tabular.py
reads/writes xlsx and csv and parses spreadsheet timestamps.
Checked against the pandas version on the same inputs: timestamp parsing
identical for 24 formats, managed-NE csv/xlsx import, stored rows and both
templates identical. Differences, all fixes:
- alarm codes in mixed text/number columns are "1001", not "1001.0"
- error row numbers are the real sheet rows (blank rows no longer shift them)
- GBK-encoded CSVs (Chinese Excel "Save as CSV") import instead of failing
- "2024年1月2日 03:04:05" style timestamps parse
Also: conftest compares parsed DB URLs (newer SQLAlchemy renders "C:" as
"C%3A").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NetX runs headless; these were ~70MB of the runtime (107MB -> 34MB) and made
CI Setups ~30MB larger than local ones. Setup: 105MB (CI) / 75MB -> 67MB.
ensurepip stays for venv creation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Prefer Python 3.12 (py -3.12 / Python312) even when another version is
first on PATH, matching the CI pin.
- Skip npm ci when node_modules already matches package-lock.json: npm ci
wipes node_modules first and a running Vite dev server leaves it
half-deleted.
- pip --no-warn-script-location: its PATH check realpath()s every entry
and aborts on a broken reparse point.
- README: local release / Forgejo / offline steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The space photo is replaced by a seeded canvas sky (nebula band, dust
lanes, stars) painted once. The card refracts the sky at its rim through
an SVG displacement filter (Chromium; plain blur elsewhere), sits further
from the right edge, and drops the glowing flare and button shadow.
Login errors now read as text instead of API codes, the last username is
remembered, and Caps Lock is flagged in the password field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Installer: dynamic light/dark Win11 style, new brand wizard images, auto
language, exclusive run mode (tray / Windows service) plus autostart and
auto-update on the Tasks page (pre-selected from what is installed on
upgrades, untouched by silent updates), 5 localized Start Menu entries.
Tray: theme-aware rounded menu with live status, icons and status-dot tray
icon; health polled off the UI thread; Settings submenu toggles autostart
and daily updates; browser opened de-elevated via explorer.
Fixes:
- tray Stop/Start was ignored in service mode (service_run restarted the
children) - all start/stop now goes through runtime_ctl.ps1
- logon tray task and SYSTEM service task were killed after 72h (default
ExecutionTimeLimit); autostart was registered for the elevating account
and opened a browser on every logon
- uninstall left the NetXTray/NetXUpdate tasks behind
- silent auto-update killed the tray without restarting it
- repair_venv.ps1 was never staged into the release
- wildcard NETX_HOST (0.0.0.0) broke health checks
- ICO frames were PNG, which System.Drawing decodes as noise; icons now
use the current brand mark
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Network Management" -> "Network", "NE Management" -> "NE Mgmt", etc.
Tiles show the full module title on hover and in the aria-label.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the card chrome: a 60px rounded tone icon with the name below, in
fixed 96px cells. Hover lifts the icon only; edit mode puts the remove
button on the icon corner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Per-user layout lives in the new app_user.prefs JSON column, read via
/v1/auth/me and written via PUT /v1/auth/me/prefs/workbench. The
workbench gets an in-place edit mode (gear -> drag to reorder, x to
remove, tray to add back, reset/done). Reset stores empty prefs so
registry changes still apply; ids of modules the user can't currently
see are kept on save.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Glass: backdrop dimmed (brightness 0.82, saturate 120%), white sheen and
inner glow removed, specular rim now a faint blue line instead of white.
- Inner borders (tiles, tables, KPI strips, tag cards, controls) use a faint
blue hairline; top-edge white highlights removed.
- Removed glows: brand mark, primary buttons, tile hover, active tag card,
task status dots (also no pulse).
- Wallpaper color pools, light streaks and dot grid at ~1/4 of before.
- Text and accent tokens one step dimmer so copy no longer glares on the
dark background.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- NE page: derive the live connect-detail row instead of syncing it in an
effect; one async path for topology deep links; memoize per-tag stats;
re-seed the form dialog during render on open; move hop form state into
lib/hopProxy so the component file only exports components.
- NE page: drop the "click a card to filter" hint; keep row actions on one
line so rows no longer double in height.
- Topology tree: rows fit the sidebar, long names ellipsize with a tooltip,
node counts stay visible; default sidebar width 260 -> 280.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Title bar: floating glass capsule aligned to each page's content edge, new
NETX mark (links-as-X), task badge, user menu with sign-out, globe locale.
- Console: resource strip on top, module launcher as the main area with
fixed-size tiles that fill rows as modules are added, task rail sized to
the left column; dropped health pill, refresh button and filler copy.
- Glass layer (theme/glass.css, loaded last): black-blue wallpaper with a
faint dot grid, clear panels with specular rims, translucent controls and
table headers; sidebar pages float their nav and work area on a 16px gutter.
- Removed ~280 lines of duplicated header CSS from primitives/theme.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add an optional ListPager meta slot so Managed NE no longer needs a separate selection row above the table.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add column filters and clearer API error mapping for NE management, tighten port validation, and slim the workbench into reusable modules with cleaner styles.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace top filter bars with shared Excel-style column menus, fix select-all and modal interactions, and use plain dropdown indicators. Apply exact-value filters before pagination and export. Isolate pytest database state and cover filter behavior.
Stale tests (behavior changed intentionally on 2026-08-12):
- Tool count is 16: suggestSinkHubs and classifyTopologyFabricNodes are
documented public tools; assert them by name.
- compose_views is no longer a public layout action; assert it is
rejected, and cover the background-job path via orbit_sweep instead.
- Dual-unit petals are nested ellipse bands with a hollow eye, not
parallel lanes; assert side split, ordering inside the portals and
zero crossings instead of portal-aligned lane ends.
Real bug (test failed since it was added on 2026-08-09):
press_hot_edges could never reel a long spoke in to its r_use target,
because max_disp (r0*0.55) is smaller than r0 - r_use. Inward pulls along
the spoke cannot fling a leaf across the bbox, so give them a cap of
r0 - r_use. On a 1483-node dev view crossings after the op drop
25501 -> 25346; a 500-node view is unchanged; runtime unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Save path: one atomic POST /views/{id}/commit (edges, ports, styles, node
add/remove, positions) replaces the multi-request save. Edge styles and
manual-edge port edits now go through dirty/undo/save instead of writing
immediately; non-manual edge ports are read-only.
Data safety: UI saves no longer clear MCP node locks or freeze the device
name into the placement label (label_override + omit-means-keep semantics,
also applied to the MCP positions tool). Adding NEs/neighbors with unsaved
edits now saves first instead of silently dropping them. Positions no longer
bypass membership caps, except persisting synthesized child-region icons.
Fixes found in acceptance: nodes added in the same commit kept (40,40)
under autoflush=False; edits on edges deleted in the same save 404'd the
whole save; box-selection drags and arrow-key moves were not marked dirty;
large canvases far from the origin opened blank and locate did nothing
because fitView waits for measurement that onlyRenderVisibleElements never
does (now fitBounds from known geometry).
Also: batch N+1 lookups in graph/positions, deterministic truncation,
outside-peer scan excludes internal edges, split TopologyPage into hooks,
fix flaky UME/LLDP port test, add scripts/topology_clear_frozen_labels.py.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
theme.css squashes every animation to 0.01ms x1 when the OS asks for reduced
motion, so the login earth jumped once and snapped back (position stuck at 0%).
The login stylesheet already intends the ambient spin to stay; restore it with a
class selector that outranks the universal rule.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The unanchored 'ume/' rule also matched web/src/features/ume/, so UmePage was
never committed and clean checkouts failed to build (App.tsx imports it).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Correctness (A): normalize port-map names with the template rules (snapshot v2,
v1 replays unchanged); protect mappings/templates that are referenced; stop
dropping edited mapping text; accept pulled-but-not-shutdown ports as migrated;
validate baseline ownership on project create; one canonical key form; fix
built-in template tolerances and upgrade old packaged values in place.
Cross-vendor identity (B): single identity pipeline for every path, per-side and
per-vendor interface rules, value maps, filters after normalization, mapping
pre-flight for compare and cutover projects, SQL eligibility fixes.
Data quality (V): no_data / suspect_parse / not_collected sheet states, command
slice coverage, directional compare modes, value-sorted duplicate pairing,
before-side raw names in results and CSV.
Robustness (H): bounded auto-run history, background evaluate/finish with
polling, manual route tables out of the acceptance gate, baseline row cache,
scoped duplicate-key failures, merged HF tasks with a per-NE session cap,
same-device cutover, explicit scope_by_port_map, read-only GETs, resolvable red
tickets.
Frontend: pre-flight report, mapping table view, template editor support for the
new rules, data-state banners. Docs: canonical field contract.
Not included: Huawei status parsers (no real samples), SQL-path route compare.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Use the shared ListPager (10/20/50/100/200 per page, remembered in
localStorage, default 20 instead of a fixed 10), keep the previous rows while the
next page loads and clamp the page when the total shrinks.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Performance: event-driven stdout pump (no polling thread per socket, no 200ms
coalescing stall), keystrokes written immediately, blocking SSH reads, bounded
deque queue with batch drain, incremental UTF-8 decode, buffered session log,
non-blocking session teardown, shorter login/settle waits, xterm WebGL renderer
and idle-time direct writes. Zero-latency fake device: echo p50 11ms -> 2.3ms,
command RTT 219ms -> 20ms, bulk output 2.1 -> 8.3 MB/s.
Audit: track the device's own input row server-side (webcrt_cmd_audit) and
resolve each Enter from the echoed line feed, so Tab, backspace, cursor-key
edits, history recall, paste, Ctrl-C and pagers record what actually ran.
Password lines are redacted; pending Enters are flushed on close.
Hop: stop closing the hop session when the target prints the same prompt as the
hop (system-view); recognise the Huawei "closed by the remote host" message.
Generic NEs that show a network prompt now get the network key map.
Adds bench_webcrt.py, fake_ssh_device.py and e2e_webcrt_input_scenarios.py.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remove permanent list-page hint banners, keep concepts in short HelpHint popovers with scannable sections and lists.
Co-authored-by: Cursor <cursoragent@cursor.com>