Skip to content

54 desktop app - #57

Merged
SaifRehman merged 191 commits into
mainfrom
54_desktop_app
Jul 6, 2026
Merged

54 desktop app#57
SaifRehman merged 191 commits into
mainfrom
54_desktop_app

Conversation

@SaifRehman

Copy link
Copy Markdown
Contributor

No description provided.

SaifRehman and others added 30 commits May 18, 2026 21:42
Approved 2026-05-18. Covers multi-project data model, per-project relay
isolation, persistent boss identity, and the bugs that depend on (or
were unblocked by) the refactor: black-screen nav, chat overflow,
"unknown" agent labels, missing comments after submit, peer ID in My
Activity, AgentFM title centering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
27 task-by-task plan against the 2026-05-18 spec. TDD where applicable,
exact code in every step, one commit per task. Boss identity risk
resolved during planning (already persistent on the Go side).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Snapshot of the desktop app source as it stands before the Phase 1
project-model refactor. Future task commits will diff cleanly against
this baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SaifRehman and others added 29 commits July 5, 2026 19:52
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…able

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sets BrowserWindow icon and app.dock.setIcon (macOS) from the AgentFM
logo so the running app shows the real icon instead of the default
Electron icon; bundles build/icon.png as an extra resource for the
packaged dock icon. The .icns baked into the .app already drives the
Finder/dock/menu icon for the installed executable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…'t Unknown

The Assets tab showed 'Unknown agent' for any artifact whose .meta.json
sidecar was missing — which happened for every non-desktop dispatch
(CLI, direct /api/execute, SDK) and any desktop dispatch whose renderer
completion path was interrupted. Root cause: identity was captured
post-hoc by the renderer, not at the source.

The boss already knows the producing worker at dispatch time
(expectArtifact(taskID, peerID) + activeWorkers/lastProfile). Write the
identity sidecar (agentName/agentDescription/agentPeerId) there, covering
all four dispatch paths (sync, async, TUI, chat). The renderer sidecar
still layers on prompt/projectName for desktop dispatches.

Not offline-related: sidecars that existed always carried the name
regardless of the agent's online state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clicking History on a peer with zero ledger entries crashed the view
with 'Cannot read properties of null (reading filter)'. Root cause:
GatherPeerEntries returns a nil slice for an empty log, and Go's
json.Marshal emits a nil slice as null, so /v1/peers/:id/log returned
{"entries":null}; PeerView then called .filter on null.

Defense in depth:
- API contract: handleLog now returns entries:[] (never null).
- Client: PeerView guards log.entries ?? [] so any null is tolerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oped boot

- Star ratings in PeerView summary (overall) + every rating entry, which
  the Activity tab shares via EntryRow.
- Peer digest shown in full and click-to-copy (was truncated).
- Fix offline-agent inconsistency: the initial backend boot now scopes to
  the ACTIVE project's ledger/relay/swarmKey (previously it booted against
  the global default ledger, showing a pile of unrelated historical
  subjects until you switched projects). main.ts reads the active project
  from settings and mirrors switchProject's config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…esh boss

Strengthens the single-entry witness acceptance test: a boss authors a
batch of distinct ratings, a witness ingests them all via gossip, every
boss goes offline, then a brand-new boss with an EMPTY ledger recovers
the COMPLETE history from the witness alone via CatchUpInbox. Passes -race.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds build/icon.ico (generated from the AgentFM logo) and a
windows-latest CI workflow that cross-builds the Windows Go backend,
builds the renderer, and produces the NSIS installer natively (no wine).

The Windows app packages fine from macOS (dist/win-unpacked runs), but
the NSIS .exe installer + exe icon-stamp require wine, which is broken on
this host — so the installer is built on a Windows runner instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Offline 'agents' with no resolvable name/description were rated peer-IDs
the boss never observed via telemetry — agent names/descriptions come
only from live WorkerProfile broadcasts, never the ledger, so there is
nothing to show for them. They rendered as nameless peer-ID cards.

Radar now only shows an offline agent if it has a resolvable identity
(name/capability/image from the API or the persisted peer-identity
cache). Agents actually seen online keep their name+description while
offline; pure trust-graph subjects are no longer surfaced as agents.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CRITICAL: acceptLocalAlert accepted two heads at DIFFERENT tree sizes as
a 'conflict', so any peer could replay two of a victim's normal, validly
-signed heads (routine log growth) to permanently brand them an
equivocator mesh-wide — a hard, unrecoverable dispatch ban. A genuine
equivocation is same TreeSize + different RootHash (a fork an honest peer
never produces); different sizes are now rejected. Test proves the
framing attack is refused while genuine equivocation still marks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HIGH: CatchUp (own-log catch-up vs the relay at boss startup) lacked the
non-advancing-cursor guard its sibling CatchUpInbox has, ran with
context.Background(), and had no ctx.Done() in the loop — a malicious
relay signing a huge-TreeSize head and serving non-advancing full pages
livelocked the startup goroutine forever. Adds the progress guard +
ctx.Done() and bounds the bootstrap call with a 2-minute timeout. Test
proves it terminates in ~ms instead of spinning to the ctx deadline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HIGH (defense-in-depth): killStaleOnPort string-interpolated an
uncoerced apiPort into an execSync shell command; electron-store has no
runtime schema and the settings:set/backend:restart IPC accepted any
value, so a compromised renderer could inject shell commands into the
main process. Adds sanitizePort (validated 1-65535 integer), guards the
execSync sink with it, and validates apiPort at the IPC boundary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
M6: no rater!=subject guard let an already-trusted peer self-rate to
amplify its own honesty score. M5: a NaN/Inf score reaching the engine
propagated through the clamp (NaN comparisons are false), bypassing the
trust gate. ingest now skips self-edges and non-finite scores.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A uint64 offset that overflows int became negative, and all[offset:]
panicked (slice bounds [-1:]). Offset is now clamped to a non-negative
bounded int.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t M1)

/api/relay/test dialed any multiaddr, an SSRF port-scan oracle when the
API is exposed off-host. It now refuses private (RFC1918/ULA), link-local,
unspecified and multicast ranges while still allowing loopback (the
desktop's local relay) and public relays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The token-less loopback boss served POSTs with a wildcard CORS policy, so
any web page the user visited could drive /api/execute (CSRF). Unsafe
methods now require an allowed Origin: absent, 'null' (Electron file://),
file:, or a loopback host. Cross-site browser origins are refused 403;
GET/HEAD are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET /v1/peers/{id}/reputation ran a full O(ledger) EigenTrust recompute
per request; a burst amplified into heavy CPU. Recompute is now throttled
to once per second, so concurrent reads coalesce.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… release script

- README: simpler star-worthy main page led by the desktop app, 4
  screenshots (radar/chat/history/assets), trimmed quick start, docs table.
- docs/DESKTOP.md: install + feature tour + CLI/API mapping.
- docs/http-api.md: add the remaining endpoints (relay/test, about, events,
  comments/self, comments/:cid[.json], peer summary, /log entry_hash).
- scripts/release.sh: cross-compile agentfm + relay for 4 platforms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SaifRehman
SaifRehman merged commit b0ea6e0 into main Jul 6, 2026
2 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant