Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Flowlight.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2252,7 +2252,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 72;
CURRENT_PROJECT_VERSION = 73;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -2267,7 +2267,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 0.16.10;
MARKETING_VERSION = 0.16.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -2313,7 +2313,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 72;
CURRENT_PROJECT_VERSION = 73;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 38RJUJHKZS;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -2328,7 +2328,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 0.16.10;
MARKETING_VERSION = 0.16.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -2393,7 +2393,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 72;
CURRENT_PROJECT_VERSION = 73;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -2414,7 +2414,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 0.16.10;
MARKETING_VERSION = 0.16.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down
12 changes: 9 additions & 3 deletions Flowlight/Analysis/AgentAttributor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,18 @@ final class AgentAttributor: @unchecked Sendable {
}

private func applyLauncher(forAgentPID pid: Int32, to key: inout FlowKey) {
guard pid > 1,
let launcher = AgentLineage.launcher(forAgentPID: pid, lookup: processLookup)
else { return }
guard pid > 1 else { return }
let launchers = AgentLineage.launchers(forAgentPID: pid, lookup: processLookup)
guard let launcher = launchers.first else { return }
key.launcherBundleID = launcher.bundleID
key.launcherName = launcher.name
key.launcherPath = launcher.argv.first
if launchers.count > 1 {
let upstream = launchers[1]
key.upstreamLauncherBundleID = upstream.bundleID
key.upstreamLauncherName = upstream.name
key.upstreamLauncherPath = upstream.argv.first
}
}

private func context(for key: FlowKey, servers: [MCPServerConfig]) -> AgentContext? {
Expand Down
9 changes: 8 additions & 1 deletion Flowlight/Analysis/MCPAttribution.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ enum AgentLineage {
/// Capture-time launcher evidence for an agent. Historical PIDs are never consulted by visualization queries.
static func launcher(forAgentPID pid: Int32, lookup: (Int32) -> ProcessSnapshot?,
maxDepth: Int = 8) -> AgentLauncher.Launcher? {
launchers(forAgentPID: pid, lookup: lookup, maxDepth: maxDepth).first
}

/// Distinct non-shell launchers, nearest first. The first item retains restart semantics; the second preserves
/// the terminal or supervisor that started that launcher for topology evidence.
static func launchers(forAgentPID pid: Int32, lookup: (Int32) -> ProcessSnapshot?,
maxDepth: Int = 8) -> [AgentLauncher.Launcher] {
var ancestors: [(pid: Int32, name: String, bundleID: String, argv: [String])] = []
var current = pid
for _ in 0..<maxDepth {
Expand All @@ -178,7 +185,7 @@ enum AgentLineage {
ancestors.append((parent.pid, parent.name, parent.bundleID, parent.argv))
current = parent.pid
}
return AgentLauncher.find(ancestors: ancestors)
return Array(AgentLauncher.findChain(ancestors: ancestors).prefix(2))
}

/// Walks up from `pid` to the nearest ancestor that is an agent. The process itself being an agent means it
Expand Down
7 changes: 6 additions & 1 deletion Flowlight/App/DemoData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@ enum DemoData {
/// Set for tools and MCP servers an agent started: (agent bundle ID, agent name, MCP server).
var parent: (id: String, name: String, mcp: String?)? = nil
var launcher: (id: String, name: String, path: String)? = nil
var upstreamLauncher: (id: String, name: String, path: String)? = nil
var routedThroughFlowlight = false

func key(_ flow: Flow) -> FlowKey {
FlowKey(pid: Int32(abs(bundleID.hashValue % 30_000) + 200), bundleID: bundleID, appName: name, appPath: path,
remoteIP: flow.ip, domain: flow.host, port: flow.port, transport: flow.transport, appProtocol: flow.proto,
channel: flow.channel, parentAgent: parent?.id, parentAgentName: parent?.name, mcpServer: parent?.mcp,
launcherBundleID: launcher?.id, launcherName: launcher?.name, launcherPath: launcher?.path,
upstreamLauncherBundleID: upstreamLauncher?.id,
upstreamLauncherName: upstreamLauncher?.name,
upstreamLauncherPath: upstreamLauncher?.path,
routeProxyBundleID: routedThroughFlowlight ? "com.flowlight.app" : nil,
routeProxyName: routedThroughFlowlight ? "Flowlight" : nil,
routeProxyPath: routedThroughFlowlight ? "/Applications/Flowlight.app" : nil)
Expand Down Expand Up @@ -111,7 +115,8 @@ enum DemoData {
Flow(host: "api.anthropic.com", ip: "198.51.100.80", port: 443, proto: "https", inRate: 700_000, outRate: 1_400_000),
Flow(host: "registry.npmjs.org", ip: "198.51.100.81", port: 443, proto: "https", inRate: 300_000, outRate: 10_000),
Flow(host: "github.com", ip: "198.51.100.11", port: 22, proto: "ssh", inRate: 50_000, outRate: 30_000),
], launcher: ("com.mitchellh.ghostty", "Ghostty", "/Applications/Ghostty.app")),
], launcher: ("herdr", "Herdr", "/Users/demo/.local/bin/herdr"),
upstreamLauncher: ("com.mitchellh.ghostty", "Ghostty", "/Applications/Ghostty.app")),
App(bundleID: "com.yetone.magpie", name: "magpie", path: "/Applications/magpie.app", weight: 0.9, flows: [
Flow(host: "api.anthropic.com", ip: "198.51.100.80", port: 443, proto: "https", inRate: 4_000_000, outRate: 8_000_000),
Flow(host: "api.openai.com", ip: "198.51.100.90", port: 443, proto: "https", inRate: 2_000_000, outRate: 3_000_000),
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,7 @@
"Fit" = "Einpassen";
"Fit the map in the window" = "Karte an das Fenster anpassen";
"Reset" = "Zurücksetzen";
"%lld selected" = "%lld ausgewählt";
"Reset zoom and position" = "Zoom und Position zurücksetzen";
"Select to inspect this connection" = "Auswählen, um diese Verbindung zu untersuchen";
"%lld exact destinations" = "%lld exakte Ziele";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@
"Fit" = "Fit";
"Fit the map in the window" = "Fit the map in the window";
"Reset" = "Reset";
"%lld selected" = "%lld selected";
"Reset zoom and position" = "Reset zoom and position";
"Select to inspect this connection" = "Select to inspect this connection";
"%lld exact destinations" = "%lld exact destinations";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,7 @@
"Fit" = "Ajustar";
"Fit the map in the window" = "Ajustar el mapa a la ventana";
"Reset" = "Restablecer";
"%lld selected" = "%lld seleccionados";
"Reset zoom and position" = "Restablecer zoom y posición";
"Select to inspect this connection" = "Selecciona para examinar esta conexión";
"%lld exact destinations" = "%lld destinos exactos";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,7 @@
"Fit" = "Ajuster";
"Fit the map in the window" = "Ajuster la carte à la fenêtre";
"Reset" = "Réinitialiser";
"%lld selected" = "%lld sélectionnés";
"Reset zoom and position" = "Réinitialiser le zoom et la position";
"Select to inspect this connection" = "Sélectionnez pour examiner cette connexion";
"%lld exact destinations" = "%lld destinations exactes";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,7 @@
"Fit" = "Adatta";
"Fit the map in the window" = "Adatta la mappa alla finestra";
"Reset" = "Ripristina";
"%lld selected" = "%lld selezionati";
"Reset zoom and position" = "Ripristina zoom e posizione";
"Select to inspect this connection" = "Seleziona per esaminare questa connessione";
"%lld exact destinations" = "%lld destinazioni esatte";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,7 @@
"Fit" = "全体表示";
"Fit the map in the window" = "マップ全体をウインドウに表示";
"Reset" = "リセット";
"%lld selected" = "%lld件を選択";
"Reset zoom and position" = "拡大率と位置をリセット";
"Select to inspect this connection" = "選択してこの接続を調べる";
"%lld exact destinations" = "%lld件の正確な宛先";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/ko.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@
"Fit" = "맞춤";
"Fit the map in the window" = "창에 지도 맞추기";
"Reset" = "재설정";
"%lld selected" = "%lld개 선택됨";
"Reset zoom and position" = "확대/축소 및 위치 재설정";
"Select to inspect this connection" = "선택하여 이 연결 조사";
"%lld exact destinations" = "정확한 대상 %lld개";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/pt-PT.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@
"Fit" = "Ajustar";
"Fit the map in the window" = "Ajustar o mapa à janela";
"Reset" = "Repor";
"%lld selected" = "%lld selecionados";
"Reset zoom and position" = "Repor ampliação e posição";
"Select to inspect this connection" = "Selecione para inspecionar esta ligação";
"%lld exact destinations" = "%lld destinos exatos";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/zh-Hans.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@
"Fit" = "适应窗口";
"Fit the map in the window" = "使地图适应窗口";
"Reset" = "重置";
"%lld selected" = "已选择 %lld 项";
"Reset zoom and position" = "重置缩放和位置";
"Select to inspect this connection" = "选择以检查此连接";
"%lld exact destinations" = "%lld 个精确目标";
Expand Down
1 change: 1 addition & 0 deletions Flowlight/Localization/zh-Hant.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@
"Fit" = "符合視窗";
"Fit the map in the window" = "使地圖符合視窗";
"Reset" = "重設";
"%lld selected" = "已選取 %lld 項";
"Reset zoom and position" = "重設縮放和位置";
"Select to inspect this connection" = "選取以檢查此連線";
"%lld exact destinations" = "%lld 個精確目的地";
Expand Down
Loading
Loading