feat(macos): per-port custom names, descriptions, folders, and type overrides - #115
Open
StreamlinedStartup wants to merge 13 commits into
Open
Conversation
Introduces the unified per-port customization record (name, description, folder, type) and routes process type resolution through it: per-port override, then legacy per-name override, then automatic detection. No behavior change while no records exist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-port customizations live in an @observable state object so edits re-render views immediately instead of waiting for the next scan. Legacy portLabels/portNotes are merged into the new record on launch (existing fields win) and then cleared; the merge is idempotent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reads each scanned PID's cwd via proc_pidinfo(PROC_PIDVNODEPATHINFO) -- one syscall per PID, no process spawns, matching the sysctl command lookup. The detected folder backs the port's effective folder unless a manual override is set. Inaccessible PIDs yield nil. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Main-window filtering passes each port's customization into PortFilter.matches, and the menu-bar quick search matches the display name. Both filter caches now key on the customizations hash so renames invalidate stale results. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The custom name replaces the process name in the table and menu-bar rows (real name stays in the detail view), nested tree rows keep it next to the port number, and table rows get a description tooltip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The detail header becomes an editable name field (placeholder = real process name), the notes section becomes a description editor backed by the customization record, and the details grid gains a per-port type picker plus a folder row with reveal-in-Finder, folder picking, and override clearing. Editors persist on focus loss. Extracting the components brings PortDetailView from 356 to 282 lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the label/note NSAlert prompts with a Customize... item that opens the main window on the port's detail editor, and rewires the type submenu to the per-port override. Deletes the now-unused label/note/ type-override AppState extensions; their Defaults keys remain for migration and the legacy per-name type fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The overlay padding inherited from the old notes editor sat ~8px below the TextEditor's insertion point, making the placeholder appear on the second line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
updatePorts diffed scans by port-pid keys only, so a rescan after a type override produced an identical key set and the guard discarded the fresh PortInfo values. The row type pill and the sidebar type sections kept reading the stale processType. Comparing full PortInfo values keeps the no-op-scan optimization while picking up per-port changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both filter cache keys sampled only the first port's hash, so a rescan that replaced a non-first PortInfo (e.g. after a type override) served stale cached results indefinitely. A portsRevision counter bumped in updatePorts now keys both caches. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merge-and-clear destroyed legacy portLabels/portNotes, so downgrading to a release that only reads those keys lost all names and notes. The migration now runs once behind a hasMigratedCustomizations flag and leaves the legacy keys intact; the flag also prevents re-merging from resurrecting values the user has since deleted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A nil per-port override fell through to the legacy per-name dictionary, so the picker showed Automatic while the legacy type silently applied, with no remaining UI path to restore detection. Choosing Automatic now also removes the legacy per-name entry, and the picker and context menu display the effective override (legacy included) instead of lying. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Customize... now navigates to a sidebar state that can actually show the port detail (favorites/watched for inactive placeholders, All Ports when a special view is selected), and selectedPort falls back to filteredPorts so synthesized inactive placeholders resolve instead of showing No Port Selected. The detail view hides Kill for inactive ports, and killPort/killPortDeep guard pid > 0 because an inactive placeholder's pid 0 would signal the entire process group. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Scope
This PR changes the macOS app only. It does not change the Windows app, the Linux app, or the Rust core. I can not test Windows or Linux.
What this PR adds
Users can customize each port. The app stores one record per port. The record holds a name, a description, a folder, and a process type.
proc_pidinfo. This adds no process spawns. The detail view shows the folder. A click reveals the folder in Finder. Users can also select a folder by hand.Data migration
Bug fixes in this PR
killPortnow rejects inactive ports and PID 0.kill(0, …)signals the whole process group.Tests
swift testpasses: 80 tests, 21 of them new.How this was built
🤖 Generated with Claude Code