Skip to content

feat(gsd-cloud): add macOS cloud monitor app and runtime telemetry#1399

Merged
jeremymcs merged 18 commits into
mainfrom
feat/gsd-cloud-monitor-release
Jul 12, 2026
Merged

feat(gsd-cloud): add macOS cloud monitor app and runtime telemetry#1399
jeremymcs merged 18 commits into
mainfrom
feat/gsd-cloud-monitor-release

Conversation

@jeremymcs

@jeremymcs jeremymcs commented Jul 11, 2026

Copy link
Copy Markdown
Member

Intent

Build and publish a native macOS menu-bar app that monitors the gsd-cloud agent's connection state and traffic, including per-project request, error, byte, active-tool, and recent activity views. Add safe start, stop, and reconnect controls that preserve pairing, multiple runtime configurations including configs sharing a directory, distinct telemetry availability semantics, notifications, failure-safe diagnostics export, launch at login, and explicit update-check states. Make it distributable as universal Intel and Apple Silicon ZIP and DMG artifacts with Developer ID signing, notarization, checksums, and a tag-triggered GitHub Release workflow. The local status contract must remain token-free and never expose pairing credentials or malformed URL secrets. Apple credentials are intentionally supplied only through GitHub Actions secrets and are not present in the repository.

What Changed

  • Added apps/gsd-cloud-monitor, a new SwiftUI menu-bar app that displays runtime connection state and per-project request/error/byte/tool/activity metrics, with start/stop/reconnect controls, launch-at-login, notifications, diagnostics export, and update-check UI, plus build/package scripts and a tag-triggered GitHub Actions release workflow producing signed/notarized universal ZIP and DMG artifacts.
  • Added packages/gsd-cloud/src/runtime-telemetry.ts and runtime-artifacts.ts, and substantially reworked cli.ts, cloud-runtime.ts, and runtime-process.ts to support safe start/stop/reconnect, multiple runtime configurations (including configs sharing a directory), start-lock recovery, and telemetry availability tracking that keeps the local status contract token-free.
  • Updated README.md, docs/README.md, and packages/gsd-cloud/README.md to document the new monitor app and CLI behavior, and expanded TypeScript and Swift test suites to cover the new runtime, telemetry, and monitor logic.

Risk Assessment

✅ Low: All four round-1 findings were fixed correctly and narrowly: disconnect now unlinks only the canonical config's telemetry file (stop still preserves it), AgentCommandRunner reads stdout/stderr on separate pipes with a DispatchGroup barrier (correct, no race, no deadlock, verified by an existing 1MB-output test), the app now uses a single AppMonitor.shared RuntimeMonitorStore for both preview and production scenes, and refresh() prunes projectTraffic to only currently-reported project IDs on successful decode while leaving the catch-path's full reset untouched. Each fix has a targeted regression test (Swift stderr-noise/failure-diagnostics tests, TS clearRuntimeTelemetry test, end-to-end disconnect status test), and no unrelated behavior changed.

Testing

Ran the Swift package's own CoreTests and ReleaseTests (both pass — the latter actually produces and checksum-verifies a signed ZIP/DMG locally), built and launched the staged app bundle in --preview-window mode against the repo's synthetic multi-project telemetry fixture and confirmed it stays running without crashing, and ran the full gsd-cloud TypeScript test suite (94/94 passing) which directly exercises token-free status persistence, credential redaction, multi-runtime configs sharing a directory, and telemetry availability semantics. I could not produce a real screenshot of the rendered DashboardView: screencapture failed ("could not create image from display") because this non-interactive session has no Screen Recording TCC permission, and a fallback off-screen SwiftUI ImageRenderer render (built by compiling the app's own source files into a throwaway harness) consistently substituted a red/yellow "blocked content" glyph instead of actual view content, regardless of code-signing — indicating this sandboxed session lacks functional WindowServer/GUI rendering access rather than any defect in the app itself. No source or test files were modified; only throwaway files in /tmp and evidence images that turned out non-representative were created and removed.

Evidence: GSDCloudMonitorReleaseTests output — local signed ZIP/DMG packaging + checksum verification
swift run GSDCloudMonitorReleaseTests
...
/…/.build/release-package/GSDCloudMonitor.app: replacing existing signature
/…/.build/release-package/GSDCloudMonitor.app: valid on disk
/…/.build/release-package/GSDCloudMonitor.app: satisfies its Designated Requirement
created: GSDCloudMonitor-0.1.0-macos.dmg
package_release: created GSDCloudMonitor-0.1.0-macos.zip
package_release: created GSDCloudMonitor-0.1.0-macos.dmg
GSDCloudMonitor-0.1.0-macos.zip: OK
GSDCloudMonitor-0.1.0-macos.dmg: OK
...hdiutil: verify: checksum of ".../GSDCloudMonitor-0.1.0-macos.dmg" is VALID
GSDCloudMonitorReleaseTests passed
- Outcome: ⚠️ 1 info across 1 run (14m47s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 4 issues found → auto-fixed ✅
  • ⚠️ packages/gsd-cloud/src/cli.ts:74 - disconnect stops the runtime and clears cloud config/credentials via clearCloudConfig, but never clears the runtime telemetry file (runtime-telemetry.ts exposes no clear/remove export at all). After a user disconnects, gsd-cloud status — and the macOS menu-bar app's local status contract that reads from it — keeps returning the last-known telemetry snapshot (runtime_id, runtime_name, sanitized gateway_url, and up to 50 recent_activity entries with real project paths and tool names) indefinitely alongside configured: false. This isn't a credential leak, but it contradicts the intended 'safe disconnect' semantics and there's no test asserting telemetry is cleared on disconnect.
  • ⚠️ apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/AgentCommandRunner.swift:82 - execute() routes both stdout and stderr through the same Pipe (lines 82-83), but runtimeIsRunning() (lines 70-74) JSON-decodes the combined buffer expecting pure JSON on stdout from the status subcommand. Any incidental stderr output from the external gsd-cloud CLI (Node deprecation/experimental warnings, a future log line) would corrupt the buffer, causing JSONDecoder to throw. The only caller, RuntimeMonitorStore.validateRuntimeStatus(), swallows this with try?, turning a legitimate running/stopped answer into nil, which maps to .stale — silently defeating the fallback validation path that exists specifically for when telemetry is unavailable.
  • ℹ️ apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/App/GSDCloudMonitorApp.swift:42 - When launched with --preview-window (the app's own documented dev workflow via script/build_and_run.sh --preview), AppDelegate creates its own RuntimeMonitorStore for the preview window (line 14), but GSDCloudMonitorApp.body still constructs the production @StateObject monitor = RuntimeMonitorStore() (line 42) because SwiftUI evaluates the Scene body regardless. This yields two live stores polling telemetry every second, each capable of firing real desktop notifications and hitting the real update-check endpoint — confined to dev-preview tooling, not production launches.
  • ℹ️ apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Stores/RuntimeMonitorStore.swift:117 - refresh() adds/updates projectTraffic[project.id] for every project currently reported by telemetry but never removes entries for project ids that stop appearing (only resetSamples(), triggered on config switch, clears the dictionary wholesale). A long-running monitor watching an agent that cycles through many ephemeral project directories over days/weeks accumulates a TrafficSeries entry per distinct id ever seen, for the life of the process. Each entry is bounded (60 samples), so impact is low, but it's unbounded in aggregate.

🔧 Fix: Applying fixes for 4 review findings; pnpm install running in background before test verification
✅ Re-checked - no issues remain.

⚠️ **Test** - 1 info
  • ℹ️ Could not produce a real screenshot/rendered-image artifact of the GSD Cloud Monitor dashboard UI. Two independent capture methods were attempted: (1) screencapture failed with "could not create image from display" — this non-interactive test session has no Screen Recording TCC permission and I did not attempt to grant it since that would mean modifying system security state; (2) an off-screen SwiftUI ImageRenderer harness (compiled from the app's own unmodified source against the fixture telemetry) built and ran successfully but consistently rendered a red/yellow "blocked content" placeholder glyph instead of the actual dashboard content, with or without ad-hoc code signing — indicating this sandboxed session lacks functional WindowServer/GUI rendering access. The app itself builds, launches, and stays alive (verified via process check) against the repo's synthetic connected-telemetry fixture, and all automated Swift and TypeScript tests pass, but no reviewer-visible visual evidence of the actual rendered UI (per-project request/error/byte/tool views, connection states, etc.) could be captured in this environment. A human should verify the dashboard visually on a normal desktop session (e.g. ./script/build_and_run.sh --preview) before relying solely on this report for the UI-facing portions of the change.
  • cd apps/gsd-cloud-monitor && swift run GSDCloudMonitorCoreTests
  • cd apps/gsd-cloud-monitor && swift run GSDCloudMonitorReleaseTests (builds app, ad-hoc signs, packages ZIP+DMG, verifies checksums)
  • cd apps/gsd-cloud-monitor && ./script/build_and_run.sh stage && open -n dist/GSDCloudMonitor.app --args --preview-window --telemetry-path Fixtures/connected-telemetry.json (manual launch check via pgrep -x GSDCloudMonitor)
  • cd packages/gsd-cloud && pnpm run test (94 node --test cases across cloud-runtime, runtime-process, runtime-telemetry, background-cli, device-flow, cloud-config, cloud-gateway-lookup, inject-gateway, executors)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.


Note

Medium Risk
Large new surface (native app controlling the cloud agent via CLI, plus signed release automation), but pairing secrets stay out of telemetry and tests cover disconnect telemetry clearing, status decoding, and packaging guards.

Overview
Introduces apps/gsd-cloud-monitor, a macOS 14+ menu-bar and dashboard app that polls the agent’s token-free cloud-runtime-status.json (no device token), shows connection/traffic and per-project metrics, and exposes Start / Stop / Reconnect, diagnostics export, notifications, multi-runtime settings, and GitHub release update checks. Packaging scripts produce universal ZIP/DMG artifacts; gsd-cloud-monitor-v* tags trigger a GitHub Actions workflow for tests, Developer ID signing, notarization, and release upload.

@opengsd/gsd-cloud gains runtime-telemetry and runtime-artifacts (hashed paths when multiple configs share a directory), a stop command that keeps pairing, status telemetry and disconnect clearing the telemetry snapshot, start-lock coordination for foreground vs background connect, and CloudRuntime hooks for connection lifecycle, byte/message counters, per-project tool activity, and flushed error state on startup failures.

Repo docs now list apps/ and link the monitor from user docs and the gsd-cloud README.

Reviewed by Cursor Bugbot for commit c5aadbc. Bugbot is set up for automated code reviews on this repo. Configure here.


View with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is enabled.

jeremymcs added 17 commits July 11, 2026 00:00
…ll running in background before test verification
@cursor

cursor Bot commented Jul 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_aa34ba1b-c63e-4994-a71c-59a4ae1e9a19)

@github-actions

Copy link
Copy Markdown
Contributor

🟡 PR Risk Report — MEDIUM

Files changed 44
Systems affected 1
Overall risk 🟡 MEDIUM

Affected Systems

Risk System
🟡 medium CLI
File Breakdown
Risk File Systems
🟡 packages/gsd-cloud/src/cli.ts CLI
.github/workflows/gsd-cloud-monitor-release.yml (unclassified)
README.md (unclassified)
apps/gsd-cloud-monitor/.gitignore (unclassified)
apps/gsd-cloud-monitor/Fixtures/connected-telemetry.json (unclassified)
apps/gsd-cloud-monitor/Package.swift (unclassified)
apps/gsd-cloud-monitor/README.md (unclassified)
apps/gsd-cloud-monitor/Resources/GSDCloudMonitor.icns (unclassified)
apps/gsd-cloud-monitor/Resources/GSDCloudMonitor.png (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/App/GSDCloudMonitorApp.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Services/NotificationService.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Stores/RuntimeMonitorStore.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Support/Formatting.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Support/RuntimeProjectState+Presentation.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Views/DashboardView.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Views/MetricCard.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Views/MonitorMenuView.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitor/Views/SettingsView.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/AgentCommandRunner.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/ConnectionTransition.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/DiagnosticsReport.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/ReleaseVersion.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/RuntimeConfiguration.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/RuntimeTelemetry.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/TrafficSeries.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCore/UpdateChecker.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorCoreTests/main.swift (unclassified)
apps/gsd-cloud-monitor/Sources/GSDCloudMonitorReleaseTests/main.swift (unclassified)
apps/gsd-cloud-monitor/script/build_and_run.sh (unclassified)
apps/gsd-cloud-monitor/script/package_release.sh (unclassified)
apps/gsd-cloud-monitor/script/stage_app_bundle.sh (unclassified)
apps/gsd-cloud-monitor/script/validate_release_version.sh (unclassified)
docs/README.md (unclassified)
packages/gsd-cloud/README.md (unclassified)
packages/gsd-cloud/package.json (unclassified)
packages/gsd-cloud/src/background-cli.test.ts (unclassified)
packages/gsd-cloud/src/cloud-runtime.test.ts (unclassified)
packages/gsd-cloud/src/cloud-runtime.ts (unclassified)
packages/gsd-cloud/src/runtime-artifacts.ts (unclassified)
packages/gsd-cloud/src/runtime-process.test.ts (unclassified)
packages/gsd-cloud/src/runtime-process.ts (unclassified)
packages/gsd-cloud/src/runtime-telemetry.test.ts (unclassified)
packages/gsd-cloud/src/runtime-telemetry.ts (unclassified)
pnpm-lock.yaml (unclassified)

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@cursor

cursor Bot commented Jul 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_d0de0d6f-2440-4cf0-8722-364bed645e35)

@jeremymcs jeremymcs merged commit b875308 into main Jul 12, 2026
15 checks passed
@jeremymcs jeremymcs deleted the feat/gsd-cloud-monitor-release branch July 12, 2026 02:47
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