diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 703c89ec..0bd1bbe1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,40 +29,32 @@ jobs: runs-on: ubuntu-24.04 outputs: app: ${{ steps.what.outputs.app }} + site: ${{ steps.what.outputs.site }} + python: ${{ steps.what.outputs.python }} + actions: ${{ steps.what.outputs.actions }} + pages: ${{ steps.what.outputs.pages }} + head_sha: ${{ steps.what.outputs.head_sha }} + tree: ${{ steps.what.outputs.tree }} + fingerprint: ${{ steps.what.outputs.fingerprint }} + schema: ${{ steps.what.outputs.schema }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: + # A pull-request check is attached to the head SHA, so build that head—not GitHub's synthetic merge ref. + ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 0 - id: what - name: Did anything outside the website change? + name: Classify the exact change + env: + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} run: | set -euo pipefail - # Anything we can't compare against runs the full build. Being wrong in that direction costs ten - # minutes; being wrong the other way ships an untested commit. - case "${{ github.event_name }}" in - pull_request) base="${{ github.event.pull_request.base.sha }}" ;; - push) base="${{ github.event.before }}" ;; - *) base="" ;; - esac - if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ] \ - || ! git cat-file -e "$base^{commit}" 2>/dev/null; then - echo "No base to compare against — building everything." - echo "app=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - changed=$(git diff --name-only "$base" "${{ github.sha }}") - echo "::group::Changed files"; echo "$changed"; echo "::endgroup::" - # The website and its sources. Everything else — Swift, project.yml, packaging, these workflows — - # is the app. project.yml is deliberately *not* here: it carries the version the site prints, but it - # also carries the build, and a version bump should be built. - rest=$(echo "$changed" | grep -Ev '^(site/|docs/|scripts/build_site\.py$|[^/]*\.md$|LICENSE$)' || true) - if [ -z "$rest" ]; then - echo "Website-only change — skipping the macOS build." - echo "app=false" >> "$GITHUB_OUTPUT" - else - echo "app=true" >> "$GITHUB_OUTPUT" - fi + python3 -I scripts/classify_changes.py \ + --repo . --base "$BASE_SHA" --head "$HEAD_SHA" --github-output "$GITHUB_OUTPUT" \ + > "$RUNNER_TEMP/change-classification.json" + cat "$RUNNER_TEMP/change-classification.json" # Seconds of Python, so it runs on everything: the site is generated from Swift sources and project.yml as well # as from site/, and "docs/ is out of date" should be caught whichever of those moved. @@ -76,6 +68,7 @@ jobs: # clone can only see one commit, so every page would look as though it changed today. - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 0 - name: Validate and verify the official rule-pack catalog @@ -161,6 +154,8 @@ jobs: name: test (${{ matrix.xcode }} Xcode) steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Select Xcode run: | @@ -184,6 +179,8 @@ jobs: scripts/test-notarize.sh scripts/test-rule-pack-policy.sh scripts/test-swift-warnings.sh + python3 -I scripts/test_classify_changes.py + python3 -I scripts/test_check_site.py python3 scripts/test_release_checks.py # This compiles a different product graph and activation path from the Developer ID build. The build clears @@ -272,3 +269,112 @@ jobs: fi set -e scripts/check-swift-warnings.sh "$LOG" + + # Exact-head evidence proves what was reviewed; this separate PR-only build proves that same head still compiles + # when combined with the current base. The trees are intentionally different, so this is not duplicate work. + merge-compatibility: + name: merge compatibility + needs: changes + if: github.event_name == 'pull_request' && needs.changes.outputs.app == 'true' + runs-on: macos-15 + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + with: + ref: refs/pull/${{ github.event.number }}/merge + + - name: Build the prospective merge + run: | + set -euo pipefail + sudo xcode-select -s "$(ls -d /Applications/Xcode*.app | sort -V | tail -1)" + xcodebuild build -project Flowlight.xcodeproj -scheme Flowlight -destination 'platform=macOS' \ + -derivedDataPath "$RUNNER_TEMP/merge-build" \ + CODE_SIGN_IDENTITY=- CODE_SIGN_STYLE=Manual DEVELOPMENT_TEAM= CODE_SIGN_ENTITLEMENTS= + + gate: + name: Review / gate + if: always() + needs: [changes, site, test, merge-compatibility] + runs-on: ubuntu-24.04 + steps: + - name: Require every applicable review job + env: + CHANGES_RESULT: ${{ needs.changes.result }} + SITE_RESULT: ${{ needs.site.result }} + TEST_RESULT: ${{ needs.test.result }} + MERGE_RESULT: ${{ needs.merge-compatibility.result }} + EVENT_NAME: ${{ github.event_name }} + APP_ROUTE: ${{ needs.changes.outputs.app }} + HEAD_SHA: ${{ needs.changes.outputs.head_sha }} + TREE: ${{ needs.changes.outputs.tree }} + FINGERPRINT: ${{ needs.changes.outputs.fingerprint }} + SCHEMA: ${{ needs.changes.outputs.schema }} + run: | + set -euo pipefail + [[ "$CHANGES_RESULT" == success ]] || { + echo "::error::Change classification did not succeed: $CHANGES_RESULT" + exit 1 + } + [[ "$SITE_RESULT" == success ]] || { + echo "::error::Site verification did not succeed: $SITE_RESULT" + exit 1 + } + case "$APP_ROUTE:$TEST_RESULT" in + true:success|false:skipped) ;; + *) + echo "::error::Application route $APP_ROUTE produced test result $TEST_RESULT." + exit 1 + ;; + esac + if [[ "$EVENT_NAME" == pull_request && "$APP_ROUTE" == true ]]; then + [[ "$MERGE_RESULT" == success ]] || { + echo "::error::Prospective-merge compatibility did not succeed: $MERGE_RESULT" + exit 1 + } + else + [[ "$MERGE_RESULT" == skipped ]] || { + echo "::error::Unexpected prospective-merge result: $MERGE_RESULT" + exit 1 + } + fi + [[ -n "$HEAD_SHA" && -n "$TREE" && -n "$FINGERPRINT" && -n "$SCHEMA" ]] || { + echo "::error::The review receipt identity is incomplete." + exit 1 + } + jq -n \ + --arg schema "$SCHEMA" \ + --arg repository "${{ github.repository }}" \ + --arg workflow ".github/workflows/ci.yml" \ + --arg event "${{ github.event_name }}" \ + --arg source_sha "$HEAD_SHA" \ + --arg source_tree "$TREE" \ + --arg app_fingerprint "$FINGERPRINT" \ + --arg app_route "$APP_ROUTE" \ + --arg changes "$CHANGES_RESULT" \ + --arg site "$SITE_RESULT" \ + --arg tests "$TEST_RESULT" \ + --arg merge_compatibility "$MERGE_RESULT" \ + --arg run_id "${{ github.run_id }}" \ + --arg run_attempt "${{ github.run_attempt }}" \ + '{schema: $schema, repository: $repository, workflow: $workflow, event: $event, + source_sha: $source_sha, source_tree: $source_tree, app_fingerprint: $app_fingerprint, + app_route: $app_route, + conclusions: {changes: $changes, site: $site, tests: $tests, + merge_compatibility: $merge_compatibility}, + run_id: $run_id, run_attempt: $run_attempt}' \ + > "$RUNNER_TEMP/review-receipt.json" + { + echo "### Review gate passed" + echo + echo "- Source: \`$HEAD_SHA\`" + echo "- Tree: \`$TREE\`" + echo "- App route: \`$APP_ROUTE\`" + echo "- App fingerprint: \`$FINGERPRINT\`" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Preserve the shadow verification receipt + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: review-receipt-${{ needs.changes.outputs.head_sha }}-${{ github.run_attempt }} + path: ${{ runner.temp }}/review-receipt.json + if-no-files-found: error + retention-days: 30 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a9fe9795..0ae7052a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -51,6 +51,9 @@ jobs: build-mode: none steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + with: + # Code scanning reports against the PR head, so compile that exact commit rather than the merge ref. + ref: ${{ github.event.pull_request.head.sha || github.sha }} # Everything that is not the compilation happens before init, and deliberately so. Once init has run, # CodeQL traces the job by preloading an x86_64 libtrace.dylib through DYLD_INSERT_LIBRARIES, which puts diff --git a/Flowlight.xcodeproj/project.pbxproj b/Flowlight.xcodeproj/project.pbxproj index d918aeec..16006e3e 100644 --- a/Flowlight.xcodeproj/project.pbxproj +++ b/Flowlight.xcodeproj/project.pbxproj @@ -2252,7 +2252,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; @@ -2267,7 +2267,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 0.17.1; + MARKETING_VERSION = 0.17.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2313,7 +2313,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 38RJUJHKZS; ENABLE_HARDENED_RUNTIME = YES; @@ -2328,7 +2328,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 0.17.1; + MARKETING_VERSION = 0.17.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2393,7 +2393,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; @@ -2414,7 +2414,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 0.17.1; + MARKETING_VERSION = 0.17.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; diff --git a/Flowlight/Analysis/Notifier.swift b/Flowlight/Analysis/Notifier.swift index 80469ca1..a81393e6 100644 --- a/Flowlight/Analysis/Notifier.swift +++ b/Flowlight/Analysis/Notifier.swift @@ -1,3 +1,4 @@ +import AppKit import Foundation import UserNotifications @@ -19,6 +20,19 @@ final class NotificationRouter: NSObject, UNUserNotificationCenterDelegate { } } +enum NotificationAuthorizationState: Equatable { + case unknown, notRequested, denied, active + + init(_ status: UNAuthorizationStatus) { + switch status { + case .notDetermined: self = .notRequested + case .denied: self = .denied + case .authorized, .provisional, .ephemeral: self = .active + @unknown default: self = .unknown + } + } +} + enum Notifier { static let updateCategory = "flowlight.update" @@ -32,6 +46,28 @@ enum Notifier { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { _, _ in } } + /// The live macOS permission state, rather than an inference from Flowlight's preference. + static func authorizationState() async -> NotificationAuthorizationState { + NotificationAuthorizationState(await UNUserNotificationCenter.current().notificationSettings().authorizationStatus) + } + + /// Used when someone switches warnings on while Flowlight is already running. Startup requests alone made the + /// toggle appear ineffective until the next launch. + static func requestAuthorizationAndWait() async -> NotificationAuthorizationState { + configure() + do { + _ = try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) + } catch { + // The settings query below remains authoritative and represents denial or an unavailable service. + } + return await authorizationState() + } + + static func openSystemNotificationSettings() { + guard let url = URL(string: "x-apple.systempreferences:com.apple.Notifications-Settings.extension") else { return } + NSWorkspace.shared.open(url) + } + /// Tells the person a new version is out. Clicking it opens the update window. static func postUpdate(version: String, summary: String?) { let content = UNMutableNotificationContent() diff --git a/Flowlight/App/AppNavigation.swift b/Flowlight/App/AppNavigation.swift index 081f2606..8f4f38d2 100644 --- a/Flowlight/App/AppNavigation.swift +++ b/Flowlight/App/AppNavigation.swift @@ -81,11 +81,18 @@ enum SidebarItem: String, CaseIterable, Identifiable { case .capture: return "antenna.radiowaves.left.and.right" } } + /// The exact visual order of the sidebar. Enum declaration order is an implementation detail and used to + /// make Connections appear fourth while Alerts still claimed ⌘4. Commands and documentation both promise + /// positional shortcuts, so derive them from the grouped navigation people can actually see. + static var sidebarOrder: [SidebarItem] { + SidebarSection.allCases.flatMap(\.items) + } + /// ⌘1…⌘9 and then ⌘0, the way every browser numbers its tabs. Nil past the tenth: there is no eleventh /// digit, and the arithmetic that assumed there was turned `10` into a `Character` and trapped the moment /// a tenth screen was added. var shortcut: KeyEquivalent? { - guard let index = Self.availableCases.firstIndex(of: self), index < 10 else { return nil } + guard let index = Self.sidebarOrder.firstIndex(of: self), index < 10 else { return nil } return KeyEquivalent(Character("\(index == 9 ? 0 : index + 1)")) } @@ -97,6 +104,20 @@ enum SidebarItem: String, CaseIterable, Identifiable { case .devices, .coverage, .capture: return .sources } } + + /// Whether the destination can honestly say that the complete active Focus scope is filtering its content. + /// Alerts can apply app targets but have no destination field, while operational/configuration screens and Ask + /// do not apply traffic scope at all. They still show the persistent Focus notice, using neutral wording. + func fullyAppliesFocus(_ scope: FocusScope) -> Bool { + switch self { + case .live, .agents, .reports, .visualize, .inspect: + return true + case .alerts: + return scope.hosts.isEmpty + case .ask, .rules, .devices, .coverage, .capture: + return false + } + } } /// The sidebar in task-focused groups rather than one long column. @@ -171,7 +192,9 @@ final class AppNavigation: ObservableObject { let restored = SidebarItem(rawValue: UserDefaults.standard.string(forKey: "FLScreen") ?? "") ?? .live return SidebarItem.availableCases.contains(restored) ? restored : .live }() - @Published var rulesTab: RulesTab = .rules + @Published var rulesTab: RulesTab = { + RulesTab(rawValue: UserDefaults.standard.string(forKey: "FLRulesTab") ?? "") ?? .rules + }() @Published var reportRequest: ReportRequest? @Published var inspectRequest: InspectRequest? @Published var ruleRequest: RuleRequest? diff --git a/Flowlight/App/FlowlightApp.swift b/Flowlight/App/FlowlightApp.swift index dfb8b06b..98d66b4b 100644 --- a/Flowlight/App/FlowlightApp.swift +++ b/Flowlight/App/FlowlightApp.swift @@ -150,7 +150,7 @@ struct FlowlightApp: App { Button(L("Report an Issue")) { NSWorkspace.shared.open(Help.issues) } } CommandGroup(before: .sidebar) { - ForEach(SidebarItem.availableCases) { item in + ForEach(SidebarItem.sidebarOrder) { item in if let shortcut = item.shortcut { Button(item.title) { nav.show(item) } .keyboardShortcut(shortcut, modifiers: .command) diff --git a/Flowlight/App/TrafficMonitor.swift b/Flowlight/App/TrafficMonitor.swift index c51121e2..e8c5c4e0 100644 --- a/Flowlight/App/TrafficMonitor.swift +++ b/Flowlight/App/TrafficMonitor.swift @@ -14,19 +14,31 @@ struct LiveTalker: Identifiable, Equatable { var id: String { bundleID } } +/// Everything the one-second timer publishes to the Live screen. Replacing one snapshot gives SwiftUI one coherent +/// update; publishing the chart, table, rates, and source state separately can reload NSTableView while its delegate +/// is still reconciling the previous publication. +private struct LiveSnapshot: Equatable { + var talkers: [LiveTalker] = [] + var series: [SeriesPoint] = [] + var currentIn: Double = 0 + var currentOut: Double = 0 + var isReceiving = false +} + /// Owns the capture source, database, anomaly engine and live state. @MainActor final class TrafficMonitor: ObservableObject { @Published private(set) var status = L("Starting…") @Published private(set) var mode: CaptureMode - @Published private(set) var talkers: [LiveTalker] = [] - @Published private(set) var liveSeries: [SeriesPoint] = [] - @Published private(set) var currentIn: Double = 0 - @Published private(set) var currentOut: Double = 0 + @Published private var live = LiveSnapshot() + var talkers: [LiveTalker] { live.talkers } + var liveSeries: [SeriesPoint] { live.series } + var currentIn: Double { live.currentIn } + var currentOut: Double { live.currentOut } + var isReceiving: Bool { live.isReceiving } @Published private(set) var sessionIn: Int64 = 0 @Published private(set) var sessionOut: Int64 = 0 @Published private(set) var unacknowledgedAlerts = 0 - @Published private(set) var isReceiving = false @Published private(set) var captureState: PacketSniffer.State = .stopped @Published private(set) var hostnamesLearned = 0 /// Share of traffic in the last hour with a hostname / with at least a network owner. @@ -91,14 +103,27 @@ final class TrafficMonitor: ObservableObject { private var windows = WindowVisibility() /// Whether anything on screen needs the live chart series and the per-app list. With nothing visible the menu - /// bar only needs the current rates, so neither is built at all. - var uiVisible: Bool { windows.isVisible } + /// bar only needs the current rates, so neither is built at all. The launch-only screenshot fixture forces the + /// complete snapshot because headless capture can see an offscreen window that AppKit correctly calls occluded. + var uiVisible: Bool { + Self.needsLiveUI( + windowVisible: windows.isVisible, + demoEnabled: DemoData.isEnabled, + forceRender: UserDefaults.standard.bool(forKey: "FLRenderLive") + ) + } + + static func needsLiveUI(windowVisible: Bool, demoEnabled: Bool, forceRender: Bool) -> Bool { + windowVisible || (demoEnabled && forceRender) + } func windowVisibility(_ window: AnyObject, isVisible: Bool) { guard windows.update(window, isVisible: isVisible) == .becameHidden else { return } // Nothing can see them, and they are rebuilt on the next tick once something can. - liveSeries = [] - talkers = [] + var next = live + next.series = [] + next.talkers = [] + if next != live { live = next } } private let liveWindow = 120 @@ -760,8 +785,10 @@ final class TrafficMonitor: ObservableObject { sessionPerApp.removeAll() sessionIn = 0 sessionOut = 0 - talkers = [] - liveSeries = [] + var next = live + next.talkers = [] + next.series = [] + if next != live { live = next } refreshAlertCount() } @@ -798,14 +825,14 @@ final class TrafficMonitor: ObservableObject { private func tickLive() { let now = Int64(Date().timeIntervalSince1970) - let receiving = lastDataAt.map { Date().timeIntervalSince($0) < 5 } ?? false - if receiving != isReceiving { isReceiving = receiving } + var next = live + next.isReceiving = lastDataAt.map { Date().timeIntervalSince($0) < 5 } ?? false // Without a window, only the last few seconds are needed for the menu bar rates. let keep = Int64(uiVisible ? liveWindow : rateWindow + 3) perSecond = perSecond.filter { $0.key > now - keep } if uiVisible { - liveSeries = ((now - Int64(liveWindow)).. 0 } .sorted { $0.rateIn + $0.rateOut > $1.rateIn + $1.rateOut } - setRates(inRate: talkers.reduce(0) { $0 + $1.rateIn }, outRate: talkers.reduce(0) { $0 + $1.rateOut }) + setRates(inRate: next.talkers.reduce(0) { $0 + $1.rateIn }, + outRate: next.talkers.reduce(0) { $0 + $1.rateOut }, in: &next) + publishLive(next) } /// Publishes rates only when they actually move, so an idle Mac doesn't redraw the menu bar every second. - private func setRates(inRate: Double, outRate: Double) { - if abs(inRate - currentIn) > max(64, currentIn * 0.02) { currentIn = inRate } - if abs(outRate - currentOut) > max(64, currentOut * 0.02) { currentOut = outRate } + private func setRates(inRate: Double, outRate: Double, in snapshot: inout LiveSnapshot) { + if abs(inRate - snapshot.currentIn) > max(64, snapshot.currentIn * 0.02) { snapshot.currentIn = inRate } + if abs(outRate - snapshot.currentOut) > max(64, snapshot.currentOut * 0.02) { snapshot.currentOut = outRate } + } + + private func publishLive(_ snapshot: LiveSnapshot) { + if snapshot != live { live = snapshot } } // MARK: Maintenance diff --git a/Flowlight/Localization/de.lproj/Localizable.strings b/Flowlight/Localization/de.lproj/Localizable.strings index fdce169e..3d41e10d 100644 --- a/Flowlight/Localization/de.lproj/Localizable.strings +++ b/Flowlight/Localization/de.lproj/Localizable.strings @@ -505,6 +505,8 @@ "via %@" = "über %@"; "Opened by %@" = "Geöffnet von %@"; "Not allowed" = "Nicht erlaubt"; +"Not requested" = "Nicht angefordert"; +"Open System Settings" = "Systemeinstellungen öffnen"; "Allow" = "Erlauben"; "Add %@ to %@'s allowlist" = "%@ zur Erlaubnisliste von %@ hinzufügen"; "Click to collapse" = "Klicken, um einzuklappen"; diff --git a/Flowlight/Localization/en.lproj/Localizable.strings b/Flowlight/Localization/en.lproj/Localizable.strings index 95234425..84397c40 100644 --- a/Flowlight/Localization/en.lproj/Localizable.strings +++ b/Flowlight/Localization/en.lproj/Localizable.strings @@ -477,6 +477,8 @@ "via %@" = "via %@"; "Opened by %@" = "Opened by %@"; "Not allowed" = "Not allowed"; +"Not requested" = "Not requested"; +"Open System Settings" = "Open System Settings"; "Allow" = "Allow"; "Add %@ to %@'s allowlist" = "Add %@ to %@'s allowlist"; "Click to collapse" = "Click to collapse"; diff --git a/Flowlight/Localization/es.lproj/Localizable.strings b/Flowlight/Localization/es.lproj/Localizable.strings index c0407caa..97a8f55a 100644 --- a/Flowlight/Localization/es.lproj/Localizable.strings +++ b/Flowlight/Localization/es.lproj/Localizable.strings @@ -505,6 +505,8 @@ "via %@" = "vía %@"; "Opened by %@" = "Abierto por %@"; "Not allowed" = "No permitido"; +"Not requested" = "No solicitado"; +"Open System Settings" = "Abrir Ajustes del Sistema"; "Allow" = "Permitir"; "Add %@ to %@'s allowlist" = "Añadir %@ a la lista de permitidos de %@"; "Click to collapse" = "Clic para contraer"; diff --git a/Flowlight/Localization/fr.lproj/Localizable.strings b/Flowlight/Localization/fr.lproj/Localizable.strings index dd4f08c2..8c1b399a 100644 --- a/Flowlight/Localization/fr.lproj/Localizable.strings +++ b/Flowlight/Localization/fr.lproj/Localizable.strings @@ -505,6 +505,8 @@ "via %@" = "via %@"; "Opened by %@" = "Ouvert par %@"; "Not allowed" = "Non autorisé"; +"Not requested" = "Non demandé"; +"Open System Settings" = "Ouvrir Réglages Système"; "Allow" = "Autoriser"; "Add %@ to %@'s allowlist" = "Ajouter %@ à la liste d'autorisation de %@"; "Click to collapse" = "Cliquer pour replier"; diff --git a/Flowlight/Localization/it.lproj/Localizable.strings b/Flowlight/Localization/it.lproj/Localizable.strings index c8d05cdf..15b09a7d 100644 --- a/Flowlight/Localization/it.lproj/Localizable.strings +++ b/Flowlight/Localization/it.lproj/Localizable.strings @@ -505,6 +505,8 @@ "via %@" = "tramite %@"; "Opened by %@" = "Aperto da %@"; "Not allowed" = "Non consentito"; +"Not requested" = "Non richiesto"; +"Open System Settings" = "Apri Impostazioni di Sistema"; "Allow" = "Consenti"; "Add %@ to %@'s allowlist" = "Aggiungi %@ all'elenco consentiti di %@"; "Click to collapse" = "Fai clic per comprimere"; diff --git a/Flowlight/Localization/ja.lproj/Localizable.strings b/Flowlight/Localization/ja.lproj/Localizable.strings index 56f7fb77..5b85ea84 100644 --- a/Flowlight/Localization/ja.lproj/Localizable.strings +++ b/Flowlight/Localization/ja.lproj/Localizable.strings @@ -505,6 +505,8 @@ "via %@" = "%@ 経由"; "Opened by %@" = "%@ が開きました"; "Not allowed" = "許可されていません"; +"Not requested" = "未要求"; +"Open System Settings" = "システム設定を開く"; "Allow" = "許可"; "Add %@ to %@'s allowlist" = "%2$@ の許可リストに %1$@ を追加"; "Click to collapse" = "クリックすると折りたたみます"; diff --git a/Flowlight/Localization/ko.lproj/Localizable.strings b/Flowlight/Localization/ko.lproj/Localizable.strings index 58059090..253bef7f 100644 --- a/Flowlight/Localization/ko.lproj/Localizable.strings +++ b/Flowlight/Localization/ko.lproj/Localizable.strings @@ -528,6 +528,8 @@ "via %@" = "%@ 경유"; "Opened by %@" = "%@에서 연결함"; "Not allowed" = "허용되지 않음"; +"Not requested" = "요청하지 않음"; +"Open System Settings" = "시스템 설정 열기"; "Allow" = "허용"; "Add %@ to %@'s allowlist" = "%2$@의 허용 목록에 %1$@ 추가"; "Click to collapse" = "클릭하면 접힙니다"; diff --git a/Flowlight/Localization/pt-PT.lproj/Localizable.strings b/Flowlight/Localization/pt-PT.lproj/Localizable.strings index b632420c..3c51cac3 100644 --- a/Flowlight/Localization/pt-PT.lproj/Localizable.strings +++ b/Flowlight/Localization/pt-PT.lproj/Localizable.strings @@ -528,6 +528,8 @@ "via %@" = "via %@"; "Opened by %@" = "Aberto por %@"; "Not allowed" = "Não permitido"; +"Not requested" = "Não solicitado"; +"Open System Settings" = "Abrir Definições do Sistema"; "Allow" = "Permitir"; "Add %@ to %@'s allowlist" = "Adicionar %@ à lista de permissões de %@"; "Click to collapse" = "Clique para recolher"; diff --git a/Flowlight/Localization/zh-Hans.lproj/Localizable.strings b/Flowlight/Localization/zh-Hans.lproj/Localizable.strings index 74ba9658..5b3fd309 100644 --- a/Flowlight/Localization/zh-Hans.lproj/Localizable.strings +++ b/Flowlight/Localization/zh-Hans.lproj/Localizable.strings @@ -528,6 +528,8 @@ "via %@" = "经由 %@"; "Opened by %@" = "由 %@ 打开"; "Not allowed" = "不允许"; +"Not requested" = "未请求"; +"Open System Settings" = "打开“系统设置”"; "Allow" = "允许"; "Add %@ to %@'s allowlist" = "将 %@ 添加到 %@ 的允许列表"; "Click to collapse" = "点按可收起"; diff --git a/Flowlight/Localization/zh-Hant.lproj/Localizable.strings b/Flowlight/Localization/zh-Hant.lproj/Localizable.strings index b6ab15ab..0c2468c6 100644 --- a/Flowlight/Localization/zh-Hant.lproj/Localizable.strings +++ b/Flowlight/Localization/zh-Hant.lproj/Localizable.strings @@ -528,6 +528,8 @@ "via %@" = "透過 %@"; "Opened by %@" = "由 %@ 開啟"; "Not allowed" = "未允許"; +"Not requested" = "尚未要求"; +"Open System Settings" = "打開「系統設定」"; "Allow" = "允許"; "Add %@ to %@'s allowlist" = "將 %@ 加入 %@ 的允許清單"; "Click to collapse" = "點按以收合"; diff --git a/Flowlight/UI/ContentView.swift b/Flowlight/UI/ContentView.swift index c40a355f..7ed9e650 100644 --- a/Flowlight/UI/ContentView.swift +++ b/Flowlight/UI/ContentView.swift @@ -6,13 +6,23 @@ struct ContentView: View { @EnvironmentObject var monitor: TrafficMonitor @EnvironmentObject var nav: AppNavigation @EnvironmentObject var updater: UpdateChecker + @EnvironmentObject var focus: FocusStore @Environment(\.openWindow) private var openWindow @Environment(\.dismissWindow) private var dismissWindow @State private var demoPluginReview: PluginPackageReview? var body: some View { NavigationSplitView { - List(selection: Binding(get: { nav.selection }, set: { if let value = $0 { nav.show(value) } })) { + List(selection: Binding(get: { nav.selection }, set: { value in + guard let value, value != nav.selection else { return } + // AppKit reports selection from inside NSTableView's delegate callback. A main-actor Task can begin + // before that callback unwinds, so dispatch explicitly to the next run-loop turn before publishing + // navigation. AppKit warns about the reentrant reload today and will assert on it in the future. + DispatchQueue.main.async { + guard value != nav.selection else { return } + nav.show(value) + } + })) { ForEach(SidebarSection.allCases) { section in Section(section.title) { ForEach(section.items) { item in @@ -86,7 +96,12 @@ struct ContentView: View { } .frame(maxWidth: .infinity, maxHeight: .infinity) .safeAreaInset(edge: .top, spacing: 0) { - if rulePacks.pendingReviewCount > 0 { packReviewBanner } + VStack(spacing: 0) { + if focus.isActive { + FocusScopeNotice(isFiltering: nav.selection.fullyAppliesFocus(focus.scope)) + } + if rulePacks.pendingReviewCount > 0 { packReviewBanner } + } } // One help button for every screen, because the documentation is grouped the way this sidebar // is: whatever is on screen, the button opens the section about it rather than the top of the page. diff --git a/Flowlight/UI/FocusView.swift b/Flowlight/UI/FocusView.swift index f9b21311..dd8684ff 100644 --- a/Flowlight/UI/FocusView.swift +++ b/Flowlight/UI/FocusView.swift @@ -31,6 +31,40 @@ struct FocusBar: View { } } +/// A persistent in-content scope notice. The sidebar footer is easy to miss once attention is in a dense table; +/// this keeps every filtered screen honest about what is currently hidden. +struct FocusScopeNotice: View { + @EnvironmentObject var focus: FocusStore + var isFiltering: Bool + @State private var editing = false + + var body: some View { + Button { editing = true } label: { + HStack(spacing: 8) { + Image(systemName: "scope") + .foregroundStyle(FL.accent) + Text(L("Focus on: %@", focus.summary)) + .font(.callout.weight(.medium)) + .lineLimit(1) + Spacer(minLength: 8) + Image(systemName: "chevron.right") + .font(.caption.weight(.semibold)) + .foregroundStyle(.secondary) + } + .padding(.horizontal, 16).padding(.vertical, 8) + .frame(maxWidth: .infinity, alignment: .leading) + .contentShape(Rectangle()) + .background(FL.accent.opacity(0.08)) + .overlay(alignment: .bottom) { Divider() } + } + .buttonStyle(.plain) + .help(isFiltering ? L("Showing only %@ — click to change", focus.summary) + : L("Focus on: %@", focus.summary)) + .accessibilityLabel(L("Focus on: %@", focus.summary)) + .popover(isPresented: $editing) { FocusEditor() } + } +} + /// Picks what Focus watches. Apps come from what's actually been talking; destinations are typed. struct FocusEditor: View { @EnvironmentObject var monitor: TrafficMonitor diff --git a/Flowlight/UI/SettingsView.swift b/Flowlight/UI/SettingsView.swift index c7c0df31..84daa6dd 100644 --- a/Flowlight/UI/SettingsView.swift +++ b/Flowlight/UI/SettingsView.swift @@ -46,7 +46,7 @@ struct SettingsView: View { } } Toggle(L("Show live rates in the menu bar"), isOn: $menuBarRates) - Toggle(L("Show notifications for warnings"), isOn: $notifications) + NotificationSettingsRow(enabled: $notifications) #if !APP_STORE UpdateSettingsRow() #endif @@ -137,6 +137,42 @@ struct SettingsView: View { } } +private struct NotificationSettingsRow: View { + @Binding var enabled: Bool + @State private var authorization: NotificationAuthorizationState = .unknown + + var body: some View { + Toggle(isOn: $enabled) { + VStack(alignment: .leading, spacing: 2) { + Text(L("Show notifications for warnings")) + Text(statusTitle) + .font(.caption) + .foregroundStyle(authorization == .denied ? FL.warning : .secondary) + } + } + .onChange(of: enabled) { _, value in + guard value else { return } + Task { authorization = await Notifier.requestAuthorizationAndWait() } + } + .task { authorization = await Notifier.authorizationState() } + .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in + Task { authorization = await Notifier.authorizationState() } + } + if authorization == .denied { + Button(L("Open System Settings")) { Notifier.openSystemNotificationSettings() } + } + } + + private var statusTitle: String { + switch authorization { + case .active: return L("Active") + case .denied: return L("Not allowed") + case .notRequested: return L("Not requested") + case .unknown: return L("Unknown") + } + } +} + struct MenuBarContent: View { @AppStorage(AnomalySettings.Keys.backgroundOnly) private var backgroundOnly = false @EnvironmentObject var monitor: TrafficMonitor diff --git a/Flowlight/UI/Visualization/TrafficGraphLayout.swift b/Flowlight/UI/Visualization/TrafficGraphLayout.swift index e648dcc4..97c1c1c7 100644 --- a/Flowlight/UI/Visualization/TrafficGraphLayout.swift +++ b/Flowlight/UI/Visualization/TrafficGraphLayout.swift @@ -810,38 +810,52 @@ enum TrafficGraphLayout { } private static func intersects(_ curve: TrafficGraphCurve, obstacles: [CGRect]) -> Bool { - func segment(_ start: CGPoint, _ end: CGPoint, intersects rect: CGRect) -> Bool { - if rect.contains(start) || rect.contains(end) { return true } - - let deltaX = end.x - start.x - let deltaY = end.y - start.y - var lower: CGFloat = 0 - var upper: CGFloat = 1 - func clip(direction: CGFloat, distance: CGFloat) -> Bool { - if abs(direction) < 0.000_001 { return distance >= 0 } - let ratio = distance / direction - if direction < 0 { - lower = max(lower, ratio) - } else { - upper = min(upper, ratio) - } - return lower <= upper - } - return clip(direction: -deltaX, distance: start.x - rect.minX) - && clip(direction: deltaX, distance: rect.maxX - start.x) - && clip(direction: -deltaY, distance: start.y - rect.minY) - && clip(direction: deltaY, distance: rect.maxY - start.y) - } - let bounds = controlBounds(curve) let relevant = obstacles.filter { bounds.intersects($0) } guard !relevant.isEmpty else { return false } - let points = (0...160).map { curve.point(at: CGFloat($0) / 160) } - return relevant.contains { obstacle in - zip(points, points.dropFirst()).contains { start, end in - segment(start, end, intersects: obstacle) + + // This runs for every routing candidate. Building a 161-point array and nested Zip2Sequence closures here + // made one ordinary 18-edge map take tens of seconds in Debug builds and time out under Xcode 16. Walk the + // same 160 line segments directly: collision precision and resulting geometry stay identical, while the hot + // path allocates nothing and can return as soon as any relevant card is hit. + var previous = curve.start + for step in 1...160 { + let current = curve.point(at: CGFloat(step) / 160) + for obstacle in relevant where segment(previous, current, intersects: obstacle) { + return true } + previous = current + } + return false + } + + private static func segment(_ start: CGPoint, _ end: CGPoint, intersects rect: CGRect) -> Bool { + if rect.contains(start) || rect.contains(end) { return true } + + let deltaX = end.x - start.x + let deltaY = end.y - start.y + var lower: CGFloat = 0 + var upper: CGFloat = 1 + return clip(direction: -deltaX, distance: start.x - rect.minX, lower: &lower, upper: &upper) + && clip(direction: deltaX, distance: rect.maxX - start.x, lower: &lower, upper: &upper) + && clip(direction: -deltaY, distance: start.y - rect.minY, lower: &lower, upper: &upper) + && clip(direction: deltaY, distance: rect.maxY - start.y, lower: &lower, upper: &upper) + } + + private static func clip( + direction: CGFloat, + distance: CGFloat, + lower: inout CGFloat, + upper: inout CGFloat + ) -> Bool { + if abs(direction) < 0.000_001 { return distance >= 0 } + let ratio = distance / direction + if direction < 0 { + lower = max(lower, ratio) + } else { + upper = min(upper, ratio) } + return lower <= upper } private static func corridorOverlap( diff --git a/FlowlightTests/AppLifecycleTests.swift b/FlowlightTests/AppLifecycleTests.swift index 668230b0..5176b562 100644 --- a/FlowlightTests/AppLifecycleTests.swift +++ b/FlowlightTests/AppLifecycleTests.swift @@ -1,4 +1,5 @@ import AppKit +import UserNotifications import XCTest @testable import Flowlight @@ -37,4 +38,11 @@ final class AppLifecycleTests: XCTestCase { XCTAssertEqual(starts, 1) } + + func testNotificationAuthorizationStatesKeepDenialDistinctFromNoRequest() { + XCTAssertEqual(NotificationAuthorizationState(.notDetermined), .notRequested) + XCTAssertEqual(NotificationAuthorizationState(.denied), .denied) + XCTAssertEqual(NotificationAuthorizationState(.authorized), .active) + XCTAssertEqual(NotificationAuthorizationState(.provisional), .active) + } } diff --git a/FlowlightTests/TrafficGraphTests.swift b/FlowlightTests/TrafficGraphTests.swift index a2bf9624..9af74a7a 100644 --- a/FlowlightTests/TrafficGraphTests.swift +++ b/FlowlightTests/TrafficGraphTests.swift @@ -3230,7 +3230,12 @@ final class TrafficGraphTests: XCTestCase { ) } let build = TrafficGraphBuilder.buildForPresentation(rows: rows) - let size = CGSize(width: 1_200, height: 900) + // TrafficGraphCanvas applies these minimums before requesting geometry. An undersized synthetic canvas can + // make padded cards form an unbroken wall, forcing the router to exhaust candidates no real view requests. + let size = CGSize( + width: max(1_200, TrafficGraphLayout.minimumCanvasWidth(for: build.map)), + height: max(900, TrafficGraphLayout.minimumCanvasHeight(for: build.map)) + ) let firstPage = TrafficGraphListPager.page(in: build.complete, visibleCount: 25) let beforeKey = TrafficGraphLayoutKey(snapshot: build.map, size: size) let beforeLayout = TrafficGraphLayout.layout( diff --git a/FlowlightTests/VisualizeNavigationTests.swift b/FlowlightTests/VisualizeNavigationTests.swift index 386d9a2b..00cb26f1 100644 --- a/FlowlightTests/VisualizeNavigationTests.swift +++ b/FlowlightTests/VisualizeNavigationTests.swift @@ -29,15 +29,40 @@ final class VisualizeNavigationTests: XCTestCase { "opening Visualize must not undo the explicit Forget privacy choice") } - func testVisualizeIsReachableFromTrafficWithoutStealingExistingShortcuts() { + func testDestinationShortcutsFollowTheVisibleSidebarOrder() { XCTAssertTrue(SidebarItem.availableCases.contains(.visualize)) XCTAssertEqual(SidebarItem.visualize.section, .traffic) XCTAssertEqual(SidebarSection.traffic.items, [.live, .agents, .reports, .visualize, .alerts]) - XCTAssertNil(SidebarItem.visualize.shortcut, - "an eleventh direct-build screen must remain reachable without hijacking Space") - XCTAssertEqual(SidebarItem.availableCases.filter { $0.shortcut == nil }, [.visualize]) - XCTAssertEqual(SidebarItem.alerts.shortcut, "4") - XCTAssertEqual(SidebarItem.rules.shortcut, "5") + XCTAssertEqual(SidebarItem.sidebarOrder, + [.live, .agents, .reports, .visualize, .alerts, + .ask, .inspect, .rules, .devices, .coverage, .capture]) + XCTAssertEqual(SidebarItem.visualize.shortcut, "4") + XCTAssertEqual(SidebarItem.alerts.shortcut, "5") + XCTAssertEqual(SidebarItem.rules.shortcut, "8") + XCTAssertEqual(SidebarItem.coverage.shortcut, "0") + XCTAssertNil(SidebarItem.capture.shortcut, + "the eleventh destination remains reachable without inventing a shortcut") + XCTAssertEqual(SidebarItem.sidebarOrder.filter { $0.shortcut == nil }, [.capture]) + } + + func testFocusNoticeClaimsFilteringOnlyWhereTheWholeScopeApplies() { + let appOnly = FocusScope(bundleIDs: ["com.example.app"]) + let destinationOnly = FocusScope(hosts: ["example.com"]) + let mixed = FocusScope(bundleIDs: ["com.example.app"], hosts: ["example.com"]) + + XCTAssertTrue(SidebarItem.live.fullyAppliesFocus(mixed)) + XCTAssertTrue(SidebarItem.agents.fullyAppliesFocus(mixed)) + XCTAssertTrue(SidebarItem.reports.fullyAppliesFocus(mixed)) + XCTAssertTrue(SidebarItem.visualize.fullyAppliesFocus(mixed)) + XCTAssertTrue(SidebarItem.inspect.fullyAppliesFocus(mixed)) + XCTAssertTrue(SidebarItem.alerts.fullyAppliesFocus(appOnly)) + XCTAssertFalse(SidebarItem.alerts.fullyAppliesFocus(destinationOnly)) + XCTAssertFalse(SidebarItem.alerts.fullyAppliesFocus(mixed)) + XCTAssertFalse(SidebarItem.ask.fullyAppliesFocus(mixed)) + XCTAssertFalse(SidebarItem.rules.fullyAppliesFocus(mixed)) + XCTAssertFalse(SidebarItem.devices.fullyAppliesFocus(mixed)) + XCTAssertFalse(SidebarItem.coverage.fullyAppliesFocus(mixed)) + XCTAssertFalse(SidebarItem.capture.fullyAppliesFocus(mixed)) } func testConnectionsKeepsTheCompatibleVisualizeRouteAndHelpAnchor() { diff --git a/FlowlightTests/WindowVisibilityTests.swift b/FlowlightTests/WindowVisibilityTests.swift index e8eef058..ac9588d4 100644 --- a/FlowlightTests/WindowVisibilityTests.swift +++ b/FlowlightTests/WindowVisibilityTests.swift @@ -21,6 +21,17 @@ final class WindowVisibilityTests: XCTestCase { XCTAssertFalse(windows.isVisible) } + @MainActor + func testHeadlessCaptureRendersLiveOnlyForTheExplicitDemoFixture() { + XCTAssertTrue(TrafficMonitor.needsLiveUI(windowVisible: true, demoEnabled: false, forceRender: false)) + XCTAssertFalse(TrafficMonitor.needsLiveUI(windowVisible: false, demoEnabled: false, forceRender: false)) + XCTAssertFalse(TrafficMonitor.needsLiveUI(windowVisible: false, demoEnabled: false, forceRender: true), + "the fixture must not disable hidden-window savings in a normal run") + XCTAssertFalse(TrafficMonitor.needsLiveUI(windowVisible: false, demoEnabled: true, forceRender: false), + "demo mode alone must not disable hidden-window savings") + XCTAssertTrue(TrafficMonitor.needsLiveUI(windowVisible: false, demoEnabled: true, forceRender: true)) + } + /// AppKit posts occlusion changes freely, including ones that repeat the current state. A counter drifted /// here; identity cannot. func testRepeatedUpdatesForOneWindowDoNotDrift() { diff --git a/docs/404.html b/docs/404.html index 3a9ce39e..8c4e1fed 100644 --- a/docs/404.html +++ b/docs/404.html @@ -86,7 +86,7 @@

That page isn't here

Try the home page,

diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index dcabb7e4..e3878414 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -471,8 +471,18 @@ GitHub release page and downloaded DMG, PKG and `SHA256SUMS.txt` checksums befor `.github/workflows/release.yml` checks the tag matches `MARKETING_VERSION`, verifies the exact commit already passed the required PR CI and CodeQL checks, then signs, notarizes and verifies with `spctl`. A tag push always stops there; -an explicit dispatch for that tag publishes the release and updates the Homebrew cask. `.github/workflows/ci.yml` -builds and tests every push and pull request, and fails if `docs/` is out of date with `site/`. +an explicit dispatch for that tag publishes the release and updates the Homebrew cask. + +Pull-request verification jobs explicitly check out the PR head SHA associated with their checks, not GitHub's +synthetic merge ref. App-changing PRs also receive one required prospective-merge build of the synthetic tree, so exact +release evidence cannot hide an incompatibility with the current base branch. `scripts/classify_changes.py` consumes the +full NUL-delimited Git diff, including both names of a rename, and permits the +website-only route only when every changed path is explicitly allowlisted. Project files, Swift/shared/test sources, +packaging, screenshots and manifests, signed catalogs, release scripts, workflows, classifier policy, and unknown paths +all take the full application route; a missing or unreadable base fails closed the same way. A website-only commit needs +no application version bump. CI still rebuilds and checks the generated site on every commit, then `Review / gate` +requires every applicable job and preserves an immutable shadow receipt containing the tested source SHA, tree, app-input +fingerprint, workflow schema, and conclusions. A cache is never release evidence. ```sh scripts/ci-secrets.sh # upload the secrets once diff --git a/docs/about/index.html b/docs/about/index.html index 86d88535..07f34f9b 100644 --- a/docs/about/index.html +++ b/docs/about/index.html @@ -153,7 +153,7 @@

Thanks

diff --git a/docs/assets/screenshots/agent-detail.png b/docs/assets/screenshots/agent-detail.png index 9d5a799a..a66c235a 100644 Binary files a/docs/assets/screenshots/agent-detail.png and b/docs/assets/screenshots/agent-detail.png differ diff --git a/docs/assets/screenshots/agent-tools.png b/docs/assets/screenshots/agent-tools.png index 0ff245f6..b89a5778 100644 Binary files a/docs/assets/screenshots/agent-tools.png and b/docs/assets/screenshots/agent-tools.png differ diff --git a/docs/assets/screenshots/agents.png b/docs/assets/screenshots/agents.png index 4dfdcb22..b8fda794 100644 Binary files a/docs/assets/screenshots/agents.png and b/docs/assets/screenshots/agents.png differ diff --git a/docs/assets/screenshots/alerts.png b/docs/assets/screenshots/alerts.png index ac4bf80b..c91db91c 100644 Binary files a/docs/assets/screenshots/alerts.png and b/docs/assets/screenshots/alerts.png differ diff --git a/docs/assets/screenshots/always-monitor.png b/docs/assets/screenshots/always-monitor.png index 8d314470..0138142c 100644 Binary files a/docs/assets/screenshots/always-monitor.png and b/docs/assets/screenshots/always-monitor.png differ diff --git a/docs/assets/screenshots/inspect.png b/docs/assets/screenshots/inspect.png index f2618a1b..ac36c821 100644 Binary files a/docs/assets/screenshots/inspect.png and b/docs/assets/screenshots/inspect.png differ diff --git a/docs/assets/screenshots/live.png b/docs/assets/screenshots/live.png index b1e81738..95cf54c6 100644 Binary files a/docs/assets/screenshots/live.png and b/docs/assets/screenshots/live.png differ diff --git a/docs/assets/screenshots/manifest.json b/docs/assets/screenshots/manifest.json index ac2049b9..eb1aa6da 100644 --- a/docs/assets/screenshots/manifest.json +++ b/docs/assets/screenshots/manifest.json @@ -3,62 +3,62 @@ "screenshots": { "agent-detail.png": { "height": 1988, - "sha256": "ac80daa5d6e4873c09ff587e5777b25d1f5ef518d40f16cead97fa16fa92519b", - "version": "0.17.1", + "sha256": "f6c14a9832867fb4c4b71a871faebebaa43252491fd4a21ad2a6b312fa1a2488", + "version": "0.17.2", "width": 3200 }, "agent-tools.png": { "height": 1424, - "sha256": "28ded766cff3de5e0b16150f9ca71aa03c1a71e7e4289a3c60c73105cd55f2c6", - "version": "0.17.1", + "sha256": "169e7dcc8bfee525318a1fd7ab61503b581f3ed7dad32c74637e3427545e047f", + "version": "0.17.2", "width": 3200 }, "agents.png": { "height": 1988, - "sha256": "474c014faa6ea955c31c2a2be33d79a107545439e48524c7e0721fdfb2c4beb6", - "version": "0.17.1", + "sha256": "f5a1a9a863a8191ffbc3d4c7d54e1136fe193c47514bf5354fd362753f18a23b", + "version": "0.17.2", "width": 3200 }, "alerts.png": { "height": 1988, - "sha256": "f85e2dbd213ce5e683e49da76b44c0632342374f3e91d70ed9d7dabbd74ac9e7", - "version": "0.17.1", + "sha256": "47c0ce19876039fa506725369ac790ea2d7c5451a855df4240c48259c4074bea", + "version": "0.17.2", "width": 3200 }, "always-monitor.png": { "height": 1988, - "sha256": "35705e00b12c44d8ff2f8b9303beb5315e57235c09f96bb9628a43c442b390ea", - "version": "0.17.1", + "sha256": "eec196792eb0f9f94a10c256aad0c6e4f8b4723079d08fdea1edcc11aea14a51", + "version": "0.17.2", "width": 3200 }, "inspect.png": { "height": 1988, - "sha256": "8e38acb6cdbc200c50f31aa4fc221db998d4fb9b2e429dc4b6140fd3eb8f3fd4", - "version": "0.17.1", + "sha256": "f4153bc86b290e1877090d4d5636d83d63059b2424d77f18994e4ef6d9bfb3db", + "version": "0.17.2", "width": 3200 }, "live.png": { "height": 1988, - "sha256": "264e60b78c786ad60d83271ab1d7ed0aae61091e6fa9c17ba2af5ca0c38ad269", - "version": "0.17.1", + "sha256": "05c875eb364e6f8f595b70951c3be89e7beeaf8941247615c461e0a7892ca068", + "version": "0.17.2", "width": 3200 }, "mcp-servers.png": { "height": 1424, - "sha256": "d48c5dcedb58d1bafc3c4bbb5bdc2024a2379550737ce019de62d642cd7f1e39", - "version": "0.17.1", + "sha256": "3d796ef6b074024c7e92f0bc55c693c65a865cfe16187a0ab951d8e7884751fc", + "version": "0.17.2", "width": 3200 }, "reports.png": { "height": 1988, - "sha256": "dfa6af58c9d504ca3a2959dda551fbec3880190e44153036917bd726c09f75db", - "version": "0.17.1", + "sha256": "bb421d7a9fdae88fe5a5ced20992aac3fb12bb747ff7ccdeee86edc331509e2c", + "version": "0.17.2", "width": 3200 }, "visualize.png": { "height": 1988, - "sha256": "fb66b26178b8e0f3928848a8073660615dbc9dbb377f65a43d49eb62352284fc", - "version": "0.17.1", + "sha256": "d83ca9a029c8d2644ee0f72a1d126b98696bc9b57341e70ce009c745fb77f958", + "version": "0.17.2", "width": 3200 } } diff --git a/docs/assets/screenshots/mcp-servers.png b/docs/assets/screenshots/mcp-servers.png index f6303813..dea97271 100644 Binary files a/docs/assets/screenshots/mcp-servers.png and b/docs/assets/screenshots/mcp-servers.png differ diff --git a/docs/assets/screenshots/reports.png b/docs/assets/screenshots/reports.png index 43b9e069..07bddeb3 100644 Binary files a/docs/assets/screenshots/reports.png and b/docs/assets/screenshots/reports.png differ diff --git a/docs/assets/screenshots/visualize.png b/docs/assets/screenshots/visualize.png index 66daff30..6993a7e4 100644 Binary files a/docs/assets/screenshots/visualize.png and b/docs/assets/screenshots/visualize.png differ diff --git a/docs/de/about/index.html b/docs/de/about/index.html index c6bdb42b..fbf4c420 100644 --- a/docs/de/about/index.html +++ b/docs/de/about/index.html @@ -152,7 +152,7 @@

Dank

diff --git a/docs/de/docs/index.html b/docs/de/docs/index.html index a9bbbcd1..6c6839a5 100644 --- a/docs/de/docs/index.html +++ b/docs/de/docs/index.html @@ -76,7 +76,7 @@

Dokumentation

Flowlight benutzen

-

Alles vom ersten Start bis zum Feinschliff an den Agentenregeln. Flowlight 0.17.1, macOS 15 oder neuer.

+

Alles vom ersten Start bis zum Feinschliff an den Agentenregeln. Flowlight 0.17.2, macOS 15 oder neuer.

diff --git a/docs/de/index.html b/docs/de/index.html index 707c55ed..c990390f 100644 --- a/docs/de/index.html +++ b/docs/de/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

Sieh, was deine Apps im Netz tun.
brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+UniversalGPL-3.0Keine Telemetrie

+

v0.17.2macOS 15+UniversalGPL-3.0Keine Telemetrie

@@ -127,7 +127,7 @@

Sieh, was deine Apps im Netz tun.
-
Flowlights Karte der KI-Aktivität. Agentenkarten führen über zugeordnete Werkzeuge und konfigurierte Gateways; die beobachtete Route von magpie über Flowlight verzweigt sich anschließend zu LLM-Diensten und Domains. Die Bandbreite zeigt das Verkehrsvolumen des Zeitraums.

Sieh die tatsächliche KI-Route: Agenten, zugeordnete Werkzeuge, konfigurierte Gateways, Flowlights beobachtete Proxy-Stufe und exakte Ziele. Die Bandbreite zeigt empfangene plus gesendete Daten im gewählten Zeitraum. Mit Demodaten.

@@ -135,7 +135,7 @@

Sieh, was deine Apps im Netz tun.
-
Flowlights Ansicht KI-Agenten. Claude Code, Cursor, Codex und ein Python-Skript mit ihren KI-Anbietern, dem woanders hin gesendeten Datenverkehr und Risikomarkierungen für SMTP, SSH, FTP, einen großen Upload und eine reine IP.

Die Ansicht KI-Agenten: der Modellanbieter jedes Agenten – und alles andere, mit dem er gesprochen hat. Mit Demodaten gezeigt.

@@ -177,17 +177,17 @@

KI-Agenten

Was tun meine Agenten, außer ihr Modell zu rufen? Anbiete

Verlauf

Wo ist alles hingegangen? Sekunde bis Jahr, gruppiert nach App, Ziel oder IP, mit Diagrammen und CSV.

⌘3
-

Warnungen

Was sah falsch aus? Nachvollziehbare Warnungen pro App, mit Ziel und Schwellenwert.

⌘4
+

Warnungen

Was sah falsch aus? Nachvollziehbare Warnungen pro App, mit Ziel und Schwellenwert.

⌘5
-

Regeln

Was habe ich verweigert – und passiert es? Jede Regel, was sie blockiert hat, und ein Verlauf jeder Entscheidung.

⌘5
+

Regeln

Was habe ich verweigert – und passiert es? Jede Regel, was sie blockiert hat, und ein Verlauf jeder Entscheidung.

⌘8

Fragen

Fragen in normaler Sprache, beantwortet aus dem Verlauf – mit jeder ausgeführten Abfrage darunter.

⌘6
-

Geräte

Bluetooth, USB und Kameras: was gekoppelt, angeschlossen oder aktiv ist und wann sich das geändert hat. Aus, bis du es einschaltest.

⌘8
+

Geräte

Bluetooth, USB und Kameras: was gekoppelt, angeschlossen oder aktiv ist und wann sich das geändert hat. Aus, bis du es einschaltest.

⌘9

Inspizieren

Optional. Was hat der Agent wirklich gesendet, und welcher Tool-Aufruf hat es ausgelöst? Entschlüsselte Anfragen, Tool-Aufrufe, Ergebnisse.

⌘7
-

Verbindungen

Was kommuniziert? Eine zoombare Sankey-Karte für App-Verkehr und nachgewiesene KI-Agentenpfade, mit exakter Listenansicht.

+

Verbindungen

Was kommuniziert? Eine zoombare Sankey-Karte für App-Verkehr und nachgewiesene KI-Agentenpfade, mit exakter Listenansicht.

⌘4 @@ -405,16 +405,16 @@

Unterstützte Tool-Aufrufe mit Netzwerkanfragen verknüpfen

Mac. Starte einen Agenten aus einem inspizierten Terminal, und der unterstützte HTTP-Verkehr des Agenten und seiner Tools wird entschlüsselt – mit den Tool-Aufrufen, die das Modell angefordert hat, und den Ergebnissen, die zurückgingen.

-
Flowlights Ansicht Inspizieren: eine Liste entschlüsselter Anfragen von Claude Code mit ihren Tool-Aufrufen und das Detail des curl-Uploads zu paste.example, ausgelöst vom Bash-Tool-Aufruf, mit den hochgeladenen Notizen im Anfrage-Body
Wo sind meine Notizen gelandet? Der curl-Upload zu paste.example, zurückverfolgt bis zum Bash-Befehl, den das Modell angefordert hat, mit dem gesendeten Body.
-
Der Tab Tools für Claude Code: Bash, Read und zwei MCP-Tools mit Beschreibungen und der Häufigkeit, mit der das Modell sie aufgerufen hat
Jedes Tool, das ein Agent dem Modell anbietet. Agenten deklarieren ihre Tools bei jedem Zug, also listet Flowlight alle auf – mit denen, die das Modell tatsächlich genutzt hat, und denen, die es nie angefasst hat.
-
Der Tab MCP-Server für Codex: ein sentry-Server, markiert als über den Anbieter, seine URL, Freigabe auf nie gesetzt, erlaubte Tools und die Tools, die er anbietet
Auch die, die du auf der Leitung nicht siehst. Bittet ein Agent den Anbieter, sich mit einem MCP-Server zu verbinden, erreicht dieser Datenverkehr deinen Mac nie. Seine Anfrage schon – also tauchen der Server, seine URL, seine Freigabeeinstellung und seine Tools trotzdem auf.
@@ -460,7 +460,7 @@

Ein Wächter, den du nicht bewachen musst

-
Das Detail von Claude Code in Flowlight: Tools und MCP-Server mit Aufrufzahlen und einem Fehlschlag, eine Erlaubnisliste und der Tab Tool-Aufrufe mit einem fehlgeschlagenen git push, einem curl-Upload zu paste.example samt Antwort und Anfrage, npm install, einem GitHub-Issue, einer Doku-Suche und einem Datei-Lesevorgang, jeweils mit Ergebnis
Ein Agent, jeder Tool-Aufruf. Der Datenverkehr der git-, curl- und MCP-Server, die Claude Code gestartet hat, zählt als Datenverkehr von Claude Code. Mit eingeschalteter HTTPS-Inspektion zeigt der Tab Tool-Aufrufe, was das Modell angefordert hat, was zurückkam und welche Anfragen jedes Tool gestellt hat: @@ -470,10 +470,10 @@

Ein Wächter, den du nicht bewachen musst

-
Die Ansicht Verlauf mit stündlichen Balken für empfangene und gesendete Daten und Ringdiagrammen für Apps, Ziele und Protokolle
Verlauf. Zoom von der Sekunde bis zum Jahr, drei Gruppierungen, Diagramme, die auch bei hunderten Apps lesbar bleiben.
-
Die Ansicht Warnungen mit Warnungen zu Agenten-Exfiltration, E-Mail, FTP, Aktivität bei Abwesenheit und einer Verkehrsspitze
Warnungen. Jede nennt die App, das Ziel und den Wert, der sie ausgelöst hat.
@@ -589,7 +589,7 @@

Wisse, was deinen Mac verlässt.

diff --git a/docs/de/privacy/index.html b/docs/de/privacy/index.html index 54efa498..c314d10a 100644 --- a/docs/de/privacy/index.html +++ b/docs/de/privacy/index.html @@ -189,7 +189,7 @@

Kontakt

diff --git a/docs/de/threat-model/index.html b/docs/de/threat-model/index.html index ebf3b396..aff08e0c 100644 --- a/docs/de/threat-model/index.html +++ b/docs/de/threat-model/index.html @@ -225,7 +225,7 @@

Eine Schwachstelle melden

diff --git a/docs/docs/index.html b/docs/docs/index.html index ea142d4f..95725c81 100644 --- a/docs/docs/index.html +++ b/docs/docs/index.html @@ -76,7 +76,7 @@

Documentation

Using Flowlight

-

Everything from the first launch to tuning the agent rules. Flowlight 0.17.1, macOS 15 or later.

+

Everything from the first launch to tuning the agent rules. Flowlight 0.17.2, macOS 15 or later.

diff --git a/docs/es/docs/index.html b/docs/es/docs/index.html index 399c321e..16085260 100644 --- a/docs/es/docs/index.html +++ b/docs/es/docs/index.html @@ -76,7 +76,7 @@

Documentación

Usar Flowlight

-

Todo, desde el primer arranque hasta el ajuste de las reglas de agentes. Flowlight 0.17.1, macOS 15 o posterior.

+

Todo, desde el primer arranque hasta el ajuste de las reglas de agentes. Flowlight 0.17.2, macOS 15 o posterior.

diff --git a/docs/es/index.html b/docs/es/index.html index 3699d75f..5c9aedb4 100644 --- a/docs/es/index.html +++ b/docs/es/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

Observa la actividad de red de tus apps.

brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+UniversalGPL-3.0Sin telemetría

+

v0.17.2macOS 15+UniversalGPL-3.0Sin telemetría

@@ -127,7 +127,7 @@

Observa la actividad de red de tus apps.
-
El mapa de actividad de IA de Flowlight. Las tarjetas de agentes se conectan mediante herramientas atribuidas y puertas de enlace configuradas; la ruta observada de magpie a Flowlight se ramifica después hacia servicios LLM y dominios. El ancho de las cintas muestra el tráfico del período.

Ve la ruta real de IA: agentes, herramientas atribuidas, puertas de enlace configuradas, la etapa de proxy observada por Flowlight y destinos exactos. El ancho muestra el total recibido y enviado en el período seleccionado. Con datos de demostración.

@@ -135,7 +135,7 @@

Observa la actividad de red de tus apps.
-
La vista Agentes de IA de Flowlight. Claude Code, Cursor, Codex y un script de Python aparecen con sus proveedores de IA, el tráfico enviado a otros sitios y distintivos de riesgo por SMTP, SSH, FTP, una subida grande y una IP directa.

La vista Agentes de IA: el proveedor de modelo de cada agente y todo lo demás con lo que habló. Con datos de demostración.

@@ -177,17 +177,17 @@

Agentes de IA

¿Qué hacen mis agentes aparte de llamar a su modelo?

Historial

¿Adónde ha ido todo? Del segundo al año, agrupado por app, destino o IP, con gráficos y CSV.

⌘3
-

Alertas

¿Qué ha pintado mal? Alertas por app, explicables, con el destino y el umbral.

⌘4
+

Alertas

¿Qué ha pintado mal? Alertas por app, explicables, con el destino y el umbral.

⌘5
-

Reglas

¿Qué he rechazado y se está cumpliendo? Cada regla, lo que ha bloqueado y un flujo con todas las decisiones.

⌘5
+

Reglas

¿Qué he rechazado y se está cumpliendo? Cada regla, lo que ha bloqueado y un flujo con todas las decisiones.

⌘8

Preguntar

Preguntas en lenguaje corriente, respondidas con el historial, y debajo cada consulta que ejecutó.

⌘6
-

Dispositivos

Bluetooth, USB y cámaras: qué está emparejado, conectado o activo y cuándo cambió. Desactivado hasta que lo actives.

⌘8
+

Dispositivos

Bluetooth, USB y cámaras: qué está emparejado, conectado o activo y cuándo cambió. Desactivado hasta que lo actives.

⌘9

Inspeccionar

Opcional. ¿Qué envió el agente en realidad y qué llamada de herramienta lo provocó? Peticiones descifradas, llamadas de herramientas, resultados.

⌘7
-

Conexiones

¿Qué se comunica? Un mapa Sankey ampliable del tráfico de apps y las rutas comprobadas de agentes de IA, con una lista exacta equivalente.

+

Conexiones

¿Qué se comunica? Un mapa Sankey ampliable del tráfico de apps y las rutas comprobadas de agentes de IA, con una lista exacta equivalente.

⌘4 @@ -405,16 +405,16 @@

Correlaciona las llamadas de herramientas compatibles con las peticiones de Mac. Arranca un agente desde un Terminal inspeccionado y el tráfico HTTP compatible del agente y de sus herramientas se descifra, con las llamadas de herramientas que pidió el modelo y los resultados que volvieron.

-
La vista Inspeccionar de Flowlight: una lista de peticiones descifradas de Claude Code con sus llamadas de herramientas, y el detalle de la subida de curl a paste.example, hecha por la llamada de herramienta Bash que la ejecutó, con las notas subidas en el cuerpo de la petición
¿Adónde han ido mis notas? La subida de curl a paste.example, rastreada hasta el comando Bash que pidió el modelo, con el cuerpo que envió.
-
La pestaña Herramientas de Claude Code: Bash, Read y dos herramientas MCP con sus descripciones y cuántas veces las llamó el modelo
Todas las herramientas que un agente ofrece al modelo. Los agentes declaran sus herramientas en cada turno, así que Flowlight las lista todas, señalando las que el modelo usó de verdad y las que no tocó nunca.
-
La pestaña Servidores MCP de Codex: un servidor sentry marcado como vía proveedor, su URL, la aprobación fijada en nunca, las herramientas permitidas y las que ofrece
Incluidos los que no se ven en el cable. Cuando un agente pide al proveedor que conecte con un servidor MCP, ese tráfico nunca llega a tu Mac. Su petición sí, así que el servidor, su URL, su ajuste de aprobación y sus herramientas siguen apareciendo.
@@ -460,7 +460,7 @@

Un monitor que no tienes que vigilar

-
El detalle de Claude Code en Flowlight: herramientas y servidores MCP con su número de llamadas y un fallo, una lista de permitidos y la pestaña Llamadas de herramientas con un git push fallido, una subida de curl a paste.example con su respuesta y su petición, un npm install, una incidencia de GitHub, una búsqueda en la documentación y una lectura de archivo, cada una con su resultado
Un agente, todas sus llamadas de herramientas. El tráfico del git, del curl y de los servidores MCP que arrancó Claude Code cuenta como de Claude Code. Con la inspección HTTPS activada, la pestaña Llamadas de herramientas muestra qué pidió el modelo, qué volvió y las peticiones que hizo cada herramienta: @@ -470,10 +470,10 @@

Un monitor que no tienes que vigilar

-
La vista Historial con barras por hora de datos recibidos y enviados y gráficos de anillo de apps, destinos y protocolos
Historial. Zoom del segundo al año, tres agrupaciones y gráficos que siguen legibles con cientos de apps.
-
La vista Alertas con alertas de exfiltración por un agente, de correo, de FTP, de actividad mientras no estás y de picos de tráfico
Alertas. Cada una nombra la app, el destino y la cifra que la activó.
@@ -589,7 +589,7 @@

Ten claro qué sale de tu Mac.

diff --git a/docs/es/privacy/index.html b/docs/es/privacy/index.html index 2e5539ae..5879c481 100644 --- a/docs/es/privacy/index.html +++ b/docs/es/privacy/index.html @@ -189,7 +189,7 @@

Contacto

diff --git a/docs/es/threat-model/index.html b/docs/es/threat-model/index.html index f0036de9..cbb65305 100644 --- a/docs/es/threat-model/index.html +++ b/docs/es/threat-model/index.html @@ -221,7 +221,7 @@

Informar de una vulnerabilidad

diff --git a/docs/fr/about/index.html b/docs/fr/about/index.html index 75e2fb3b..83bfb24f 100644 --- a/docs/fr/about/index.html +++ b/docs/fr/about/index.html @@ -152,7 +152,7 @@

Remerciements

diff --git a/docs/fr/docs/index.html b/docs/fr/docs/index.html index 7cf8246b..02e33fb2 100644 --- a/docs/fr/docs/index.html +++ b/docs/fr/docs/index.html @@ -76,7 +76,7 @@

Documentation

Utiliser Flowlight

-

Tout, du premier lancement au réglage des règles des agents. Flowlight 0.17.1, macOS 15 ou version ultérieure.

+

Tout, du premier lancement au réglage des règles des agents. Flowlight 0.17.2, macOS 15 ou version ultérieure.

diff --git a/docs/fr/index.html b/docs/fr/index.html index 2f52c8c9..fac96d23 100644 --- a/docs/fr/index.html +++ b/docs/fr/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

Voyez l’activité réseau de vos apps.

brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+UniverselGPL-3.0Sans télémétrie

+

v0.17.2macOS 15+UniverselGPL-3.0Sans télémétrie

@@ -127,7 +127,7 @@

Voyez l’activité réseau de vos apps.
-
La carte d’activité IA de Flowlight. Les cartes des agents passent par des outils attribués et des passerelles configurées ; la route observée de magpie vers Flowlight se ramifie ensuite vers les services LLM et les domaines. La largeur des rubans indique le trafic de la période.

Voyez la route IA réelle : agents, outils attribués, passerelles configurées, étape proxy observée par Flowlight et destinations exactes. La largeur indique le total reçu et envoyé pendant la période sélectionnée. Avec des données de démonstration.

@@ -135,7 +135,7 @@

Voyez l’activité réseau de vos apps.
-
La vue Agents IA de Flowlight. Claude Code, Cursor, Codex et un script Python y figurent avec leurs fournisseurs d’IA, le trafic envoyé ailleurs et des badges de risque pour SMTP, SSH, FTP, un envoi volumineux et une IP brute.

La vue Agents IA : le fournisseur de modèle de chaque agent, et tout le reste de ce qu’il a contacté. Avec des données de démonstration.

@@ -177,17 +177,17 @@

Agents IA

Que font mes agents en plus d’appeler leur modèle ?

Historique

Où tout cela est-il parti ? De la seconde à l’année, par app, par destination ou par IP, avec graphiques et CSV.

⌘3
-

Alertes

Qu’est-ce qui clochait ? Des alertes explicables, par app, avec la destination et le seuil.

⌘4
+

Alertes

Qu’est-ce qui clochait ? Des alertes explicables, par app, avec la destination et le seuil.

⌘5
-

Règles

Qu’ai-je refusé, et est-ce bien appliqué ? Chaque règle, ce qu’elle a bloqué, et le flux de toutes les décisions.

⌘5
+

Règles

Qu’ai-je refusé, et est-ce bien appliqué ? Chaque règle, ce qu’elle a bloqué, et le flux de toutes les décisions.

⌘8

Demander

Des questions en langage courant, auxquelles l’historique répond — avec la liste des requêtes exécutées juste en dessous.

⌘6
-

Appareils

Bluetooth, USB et caméras : ce qui est appairé, branché ou actif, et quand cela a changé. Désactivé jusqu’à ce que vous l’activiez.

⌘8
+

Appareils

Bluetooth, USB et caméras : ce qui est appairé, branché ou actif, et quand cela a changé. Désactivé jusqu’à ce que vous l’activiez.

⌘9

Inspecter

Facultatif. Qu’a réellement envoyé l’agent, et quel appel d’outil en est la cause ? Requêtes déchiffrées, appels d’outils, résultats.

⌘7
-

Connexions

Qui communique ? Une carte Sankey zoomable du trafic des apps et des chemins attestés des agents IA, avec une liste exacte équivalente.

+

Connexions

Qui communique ? Une carte Sankey zoomable du trafic des apps et des chemins attestés des agents IA, avec une liste exacte équivalente.

⌘4 @@ -405,16 +405,16 @@

Reliez les appels d’outils pris en charge aux requêtes réseau

Mac. Lancez un agent depuis un Terminal inspecté et le trafic HTTP pris en charge de l’agent et de ses outils est déchiffré, avec les appels d’outils que le modèle a demandés et les résultats qui lui sont revenus.

-
La vue Inspecter de Flowlight : une liste de requêtes Claude Code déchiffrées avec leurs appels d’outils, et le détail de l’envoi de curl vers paste.example, effectué par l’appel d’outil Bash qui l’a lancé, avec les notes envoyées dans le corps de la requête
Où sont parties mes notes ? L’envoi de curl vers paste.example, remonté jusqu’à la commande Bash demandée par le modèle, avec le corps transmis.
-
L’onglet Outils de Claude Code : Bash, Read et deux outils MCP avec leurs descriptions et le nombre d’appels du modèle pour chacun
Tous les outils qu’un agent propose au modèle. Les agents déclarent leurs outils à chaque tour, donc Flowlight les liste tous, en distinguant ceux que le modèle a vraiment utilisés de ceux qu’il n’a jamais touchés.
-
L’onglet Serveurs MCP de Codex : un serveur sentry marqué via le fournisseur, son URL, l’approbation réglée sur jamais, les outils autorisés et les outils qu’il propose
Y compris ceux qu’on ne voit pas passer sur le réseau. Quand un agent demande au fournisseur de se connecter à un serveur MCP, ce trafic ne passe jamais par votre Mac. Sa requête, si : le serveur, son URL, son réglage d’approbation et ses outils apparaissent quand même.
@@ -460,7 +460,7 @@

Un moniteur que vous n’avez pas à surveiller

-
Le détail de Claude Code dans Flowlight : Outils et serveurs MCP avec le nombre d’appels et un échec, une liste d’autorisation, et l’onglet Appels d’outils listant un git push en échec, un envoi curl vers paste.example avec sa réponse et sa requête, un npm install, un ticket GitHub, une recherche dans la documentation et une lecture de fichier, chacun avec son résultat
Un agent, tous ses appels d’outils. Le trafic des git, curl et serveurs MCP lancés par Claude Code compte comme celui de Claude Code. Avec l’inspection HTTPS activée, l’onglet Appels d’outils montre ce que le modèle a demandé, ce qui est revenu et les requêtes émises par chaque outil : @@ -470,10 +470,10 @@

Un moniteur que vous n’avez pas à surveiller

-
La vue Historique avec les barres horaires des données reçues et envoyées et des anneaux pour les apps, les destinations et les protocoles
Historique. Zoom de la seconde à l’année, trois regroupements, des graphiques qui restent lisibles avec des centaines d’apps.
-
La vue Alertes listant des alertes d’exfiltration par un agent, d’e-mail, de FTP, d’activité pendant une absence et de pic de trafic
Alertes. Chacune nomme l’app, la destination et le chiffre qui l’a déclenchée.
@@ -589,7 +589,7 @@

Sachez ce qui quitte votre Mac.

diff --git a/docs/fr/privacy/index.html b/docs/fr/privacy/index.html index d58dadb0..9a717e0b 100644 --- a/docs/fr/privacy/index.html +++ b/docs/fr/privacy/index.html @@ -189,7 +189,7 @@

Contact

diff --git a/docs/fr/threat-model/index.html b/docs/fr/threat-model/index.html index 8bd9ca95..1370c3cf 100644 --- a/docs/fr/threat-model/index.html +++ b/docs/fr/threat-model/index.html @@ -224,7 +224,7 @@

Signaler une vulnérabilité

diff --git a/docs/index.html b/docs/index.html index e14554a8..f6b9eb2f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

See your apps' network activity.
brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+UniversalGPL-3.0No telemetry

+

v0.17.2macOS 15+UniversalGPL-3.0No telemetry

@@ -127,7 +127,7 @@

See your apps' network activity.
-
Flowlight's AI activity map. Agent cards connect through attributed tools and configured gateways; the observed magpie to Flowlight route then branches to LLM services and domains, with ribbon width showing period traffic volume.

See the real AI route: agents, attributed tools, configured gateways, Flowlight's observed proxy stage, and exact destinations. Ribbon width shows total received plus sent traffic for the selected period. Shown with demo data.

@@ -135,7 +135,7 @@

See your apps' network activity.
-
Flowlight's AI Agents view. Claude Code, Cursor, Codex and a Python script are listed with their AI providers, traffic sent elsewhere and risk badges for SMTP, SSH, FTP, a large upload and a raw IP.

The AI Agents view: each agent's model provider, and everything else it talked to. Shown with demo data.

@@ -143,7 +143,7 @@

See your apps' network activity.
-
The AI Agents view offering to always monitor Windsurf, and confirming Flowlight is keeping Claude Code and Cursor routed through it on every launch, each with a one-click Stop Monitoring.

Always monitor an agent: Flowlight writes the proxy into the agent's own settings so it routes through on every launch, and says what it's keeping — stop any of it in a click. Shown with demo data.

@@ -185,17 +185,17 @@

AI Agents

What are my agents doing besides calling their model? Provi

History

Where did it all go? From 15 minutes through all history, grouped by app, destination or IP, with charts and CSV.

⌘3
-

Alerts

What looked wrong? Explainable, per-app alerts with the destination and the threshold.

⌘4
+

Alerts

What looked wrong? Explainable, per-app alerts with the destination and the threshold.

⌘5
-

Rules

What have I refused, and is it happening? Every rule, what each has blocked, and a feed of every decision.

⌘5
+

Rules

What have I refused, and is it happening? Every rule, what each has blocked, and a feed of every decision.

⌘8

Ask

Questions in plain language, answered from the history — with every query it ran listed underneath.

⌘6
-

Devices

Bluetooth, USB, and cameras: what's paired, what's attached or active, and when that changed. Off until you turn it on.

⌘8
+

Devices

Bluetooth, USB, and cameras: what's paired, what's attached or active, and when that changed. Off until you turn it on.

⌘9

Inspect

Optional. What did the agent actually send, and which tool call made it? Decrypted requests, tool calls, results.

⌘7
-

Connections

What is communicating? A zoomable Sankey map for app traffic and proved AI-agent paths, with exact list parity.

+

Connections

What is communicating? A zoomable Sankey map for app traffic and proved AI-agent paths, with exact list parity.

⌘4 @@ -427,16 +427,16 @@

Correlate supported tool calls with network requests

Mac. Start an agent from an inspected Terminal and supported HTTP traffic from the agent and its tools is decrypted, with tool calls the model asked for and the results that went back.

-
Flowlight's Inspect view: a list of decrypted Claude Code requests with their tool calls, and the detail of curl's upload to paste.example, made by the Bash tool call that ran it, with the uploaded notes in the request body
Where did my notes go? curl's upload to paste.example, traced to the Bash command the model asked for, with the body it sent.
-
The Tools tab for Claude Code: Bash, Read and two MCP tools with descriptions and how often the model called each
Every tool an agent offers the model. Agents declare their tools on each turn, so Flowlight lists them all, with the ones the model actually used and the ones it never touched.
-
The MCP servers tab for Codex: a sentry server marked via provider, its URL, approval set to never, allowed tools and the tools it offers
Including the ones you can't see on the wire. When an agent asks the provider to connect to an MCP server, that traffic never reaches your Mac. Its request does, so the server, its URL, its approval setting and its tools still show up.
@@ -482,7 +482,7 @@

A monitor you don't have to monitor

-
Claude Code's detail in Flowlight: Tools and MCP servers with call counts and one failure, an allowlist, and the Tool calls tab listing a failed git push, a curl upload to paste.example with its response and request, npm install, a GitHub issue, a docs search and a file read, each with its result
One agent, every tool call. Traffic from the git, curl and MCP servers Claude Code started counts as Claude Code's. With HTTPS inspection on, the Tool calls tab shows what the model asked for, what came back, and the requests each tool made: @@ -492,10 +492,10 @@

A monitor you don't have to monitor

-
History view with hourly received and sent bars and donut charts of apps, destinations and protocols
History. Preset ranges, a draggable navigator, three groupings, and charts that stay readable with hundreds of apps.
-
Alerts view listing agent exfiltration, email, FTP, while-away and traffic spike alerts
Alerts. Each one names the app, the destination and the number that tripped it.
@@ -612,7 +612,7 @@

Know what leaves your Mac.

diff --git a/docs/it/about/index.html b/docs/it/about/index.html index 9c95eb6b..4f7c5ed3 100644 --- a/docs/it/about/index.html +++ b/docs/it/about/index.html @@ -152,7 +152,7 @@

Ringraziamenti

diff --git a/docs/it/docs/index.html b/docs/it/docs/index.html index 62c23a43..277da81f 100644 --- a/docs/it/docs/index.html +++ b/docs/it/docs/index.html @@ -76,7 +76,7 @@

Documentazione

Usare Flowlight

-

Tutto, dal primo avvio alla messa a punto delle regole per gli agenti. Flowlight 0.17.1, macOS 15 o successivo.

+

Tutto, dal primo avvio alla messa a punto delle regole per gli agenti. Flowlight 0.17.2, macOS 15 o successivo.

diff --git a/docs/it/index.html b/docs/it/index.html index 23d137d8..01e0c25f 100644 --- a/docs/it/index.html +++ b/docs/it/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

Vedi la rete delle tue app.
Ca

brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+UniversaleGPL-3.0Nessuna telemetria

+

v0.17.2macOS 15+UniversaleGPL-3.0Nessuna telemetria

@@ -127,7 +127,7 @@

Vedi la rete delle tue app.
Ca
-
La mappa dell’attività IA di Flowlight. Le schede degli agenti passano attraverso strumenti attribuiti e gateway configurati; il percorso osservato da magpie a Flowlight si dirama poi verso servizi LLM e domini. La larghezza dei nastri mostra il traffico del periodo.

Vedi il percorso IA reale: agenti, strumenti attribuiti, gateway configurati, lo stadio proxy osservato da Flowlight e le destinazioni esatte. La larghezza mostra il totale ricevuto e inviato nel periodo selezionato. Con dati dimostrativi.

@@ -135,7 +135,7 @@

Vedi la rete delle tue app.
Ca
-
La vista Agenti IA di Flowlight. Claude Code, Cursor, Codex e uno script Python sono elencati con i loro provider IA, il traffico inviato altrove e i contrassegni di rischio per SMTP, SSH, FTP, un caricamento di grandi dimensioni e un IP grezzo.

La vista Agenti IA: il provider del modello di ogni agente e tutto il resto con cui ha parlato. Mostrata con dati dimostrativi.

@@ -177,17 +177,17 @@

Agenti IA

Cosa fanno i miei agenti oltre a chiamare il modello? Provi

Cronologia

Dove è finito tutto? Dal secondo all'anno, per app, destinazione o IP, con grafici e CSV.

⌘3
-

Avvisi

Cosa non tornava? Avvisi per app, spiegati, con la destinazione e la soglia.

⌘4
+

Avvisi

Cosa non tornava? Avvisi per app, spiegati, con la destinazione e la soglia.

⌘5
-

Regole

Cosa ho rifiutato, e sta funzionando? Ogni regola, che cosa ha bloccato e il flusso di tutte le decisioni.

⌘5
+

Regole

Cosa ho rifiutato, e sta funzionando? Ogni regola, che cosa ha bloccato e il flusso di tutte le decisioni.

⌘8

Chiedi

Domande in linguaggio naturale, con risposte tratte dalla cronologia e sotto l'elenco di tutte le query eseguite.

⌘6
-

Dispositivi

Bluetooth, USB e fotocamere: che cosa è abbinato, collegato o attivo e quando è cambiato. Disattivato finché non lo attivi.

⌘8
+

Dispositivi

Bluetooth, USB e fotocamere: che cosa è abbinato, collegato o attivo e quando è cambiato. Disattivato finché non lo attivi.

⌘9

Ispeziona

Opzionale. Cosa ha inviato davvero l'agente, e quale chiamata a uno strumento l'ha prodotta? Richieste decifrate, chiamate agli strumenti, risultati.

⌘7
-

Connessioni

Che cosa comunica? Una mappa Sankey ingrandibile del traffico delle app e dei percorsi comprovati degli agenti IA, con un elenco esatto equivalente.

+

Connessioni

Che cosa comunica? Una mappa Sankey ingrandibile del traffico delle app e dei percorsi comprovati degli agenti IA, con un elenco esatto equivalente.

⌘4
@@ -405,16 +405,16 @@

Collega le chiamate agli strumenti supportate alle richieste di rete

sul tuo Mac. Avvia un agente da un Terminale ispezionato e il traffico HTTP supportato dell'agente e dei suoi strumenti viene decifrato, con le chiamate agli strumenti richieste dal modello e i risultati tornati indietro.

-
La vista Ispeziona di Flowlight: un elenco di richieste decifrate di Claude Code con le loro chiamate agli strumenti e il dettaglio del caricamento di curl verso paste.example, prodotto dalla chiamata allo strumento Bash che lo ha eseguito, con le note caricate nel corpo della richiesta
Dove sono finite le mie note? Il caricamento di curl verso paste.example, risalendo al comando Bash richiesto dal modello, con il corpo che ha inviato.
-
Il pannello Strumenti per Claude Code: Bash, Read e due strumenti MCP con le descrizioni e quante volte il modello ha chiamato ciascuno
Ogni strumento che un agente offre al modello. Gli agenti dichiarano i loro strumenti a ogni turno, così Flowlight li elenca tutti, indicando quelli che il modello ha davvero usato e quelli che non ha mai toccato.
-
Il pannello Server MCP per Codex: un server sentry contrassegnato come «tramite provider», il suo URL, approvazione impostata su «mai», gli strumenti consentiti e quelli che offre
Compresi quelli che non vedi passare in rete. Quando un agente chiede al provider di collegarsi a un server MCP, quel traffico non arriva mai al tuo Mac. La sua richiesta sì, così il server, il suo URL, la sua impostazione di approvazione e i suoi strumenti compaiono comunque.
@@ -460,7 +460,7 @@

Un monitoraggio che non devi monitorare

-
Il dettaglio di Claude Code in Flowlight: strumenti e server MCP con il numero di chiamate e un errore, un elenco consentiti e il pannello Chiamate agli strumenti con un git push fallito, un caricamento curl verso paste.example con la sua risposta e la sua richiesta, npm install, un issue su GitHub, una ricerca nella documentazione e la lettura di un file, ciascuno con il proprio risultato
Un agente, tutte le chiamate agli strumenti. Il traffico di git, curl e dei server MCP avviati da Claude Code conta come traffico di Claude Code. Con l'ispezione HTTPS attiva, il pannello Chiamate agli strumenti mostra che cosa ha chiesto il modello, che cosa è tornato indietro e le richieste fatte da ogni strumento: @@ -470,10 +470,10 @@

Un monitoraggio che non devi monitorare

-
La vista Cronologia con le barre orarie dei dati ricevuti e inviati e i grafici ad anello di app, destinazioni e protocolli
Cronologia. Zoom dal secondo all'anno, tre raggruppamenti, grafici che restano leggibili con centinaia di app.
-
La vista Avvisi con avvisi di esfiltrazione da parte di un agente, e-mail, FTP, attività mentre sei via e picco di traffico
Avvisi. Ognuno indica l'app, la destinazione e il numero che lo ha fatto scattare.
@@ -589,7 +589,7 @@

Sappi che cosa esce dal tuo Mac.

diff --git a/docs/it/privacy/index.html b/docs/it/privacy/index.html index 901cfe67..bf7af1b0 100644 --- a/docs/it/privacy/index.html +++ b/docs/it/privacy/index.html @@ -189,7 +189,7 @@

Contatti

diff --git a/docs/it/threat-model/index.html b/docs/it/threat-model/index.html index a78636b9..3faad9f4 100644 --- a/docs/it/threat-model/index.html +++ b/docs/it/threat-model/index.html @@ -223,7 +223,7 @@

Segnalare una vulnerabilità

diff --git a/docs/ja/about/index.html b/docs/ja/about/index.html index b3993bc6..768e74a2 100644 --- a/docs/ja/about/index.html +++ b/docs/ja/about/index.html @@ -153,7 +153,7 @@

謝辞

diff --git a/docs/ja/docs/index.html b/docs/ja/docs/index.html index 57169882..e11c216b 100644 --- a/docs/ja/docs/index.html +++ b/docs/ja/docs/index.html @@ -76,7 +76,7 @@

ドキュメント

Flowlight の使い方

-

初回起動からエージェントのルールの調整まで、すべてここに。Flowlight 0.17.1、macOS 15 以降。

+

初回起動からエージェントのルールの調整まで、すべてここに。Flowlight 0.17.2、macOS 15 以降。

diff --git a/docs/ja/index.html b/docs/ja/index.html index de4ca342..b16f69a6 100644 --- a/docs/ja/index.html +++ b/docs/ja/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

アプリの通信が見える。
brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+ユニバーサルGPL-3.0テレメトリなし

+

v0.17.2macOS 15+ユニバーサルGPL-3.0テレメトリなし

@@ -127,7 +127,7 @@

アプリの通信が見える。
-
Flowlight の AI アクティビティマップ。エージェントカードは関連付けられたツールと設定済みゲートウェイを経由し、観測された magpie から Flowlight への経路が LLM サービスとドメインへ分岐します。帯の幅は期間内の通信量を示します。

実際の AI 経路を確認できます。エージェント、関連付けられたツール、設定済みゲートウェイ、Flowlight が観測したプロキシ段階、正確な接続先を表示。帯の幅は選択期間の受信量と送信量の合計です。デモデータで表示しています。

@@ -135,7 +135,7 @@

アプリの通信が見える。
-
Flowlight の AI エージェントビュー。Claude Code、Cursor、Codex、Python スクリプトが、利用している AI プロバイダ、ほかへ送ったトラフィック、SMTP・SSH・FTP・大量送信・生 IP のリスクバッジとともに並んでいます。

AI エージェントビュー。各エージェントのモデルプロバイダと、それ以外に通信した相手のすべて。デモデータで表示しています。

@@ -177,17 +177,17 @@

AI エージェント

エージェントはモデルを呼ぶ以外

履歴

結局どこへ行った?秒から年まで、アプリ・接続先・IP でグループ化、グラフと CSV 付き。

⌘3
-

アラート

何がおかしかった?理由がわかるアプリ単位のアラートに、接続先としきい値を添えて。

⌘4
+

アラート

何がおかしかった?理由がわかるアプリ単位のアラートに、接続先としきい値を添えて。

⌘5
-

ルール

何を拒否し、それは効いている?すべてのルール、それぞれがブロックしたもの、判定の履歴。

⌘5
+

ルール

何を拒否し、それは効いている?すべてのルール、それぞれがブロックしたもの、判定の履歴。

⌘8

質問

ふつうの言葉で聞けば、履歴から答えます。実行したクエリもすべて下に並びます。

⌘6
-

デバイス

Bluetooth、USB、カメラ。何がペアリング、接続、使用中で、いつ変わったか。自分でオンにするまではオフです。

⌘8
+

デバイス

Bluetooth、USB、カメラ。何がペアリング、接続、使用中で、いつ変わったか。自分でオンにするまではオフです。

⌘9

インスペクト

任意。エージェントは実際に何を送り、どのツール呼び出しが原因だった?復号したリクエスト、ツール呼び出し、結果。

⌘7
-

接続

何が通信している?アプリのトラフィックと確認済み AI エージェント経路を、ズームできる Sankey マップと同じ内容のリストで表示します。

+

接続

何が通信している?アプリのトラフィックと確認済み AI エージェント経路を、ズームできる Sankey マップと同じ内容のリストで表示します。

⌘4

@@ -404,16 +404,16 @@

対応するツール呼び出しとネットワークリクエストを結 インスペクト対象のターミナルからエージェントを起動すれば、エージェントとそのツールの対応 HTTP 通信が復号され、モデルが要求した ツール呼び出しと、返っていった結果まで見えます。

-
Flowlight のインスペクトビュー。復号された Claude Code のリクエストとそのツール呼び出しの一覧、そして paste.example への curl の送信の詳細。実行元となった Bash のツール呼び出しと、リクエスト本文に入った送信済みのメモが表示されています
あのメモはどこへ行った?paste.example への curl の送信を、モデルが要求した Bash コマンドまでたどり、 送られた本文まで示します。
-
Claude Code のツールタブ。Bash、Read と 2 つの MCP ツールが、説明とモデルが呼び出した回数とともに並んでいます
エージェントがモデルに渡すツールのすべて。エージェントはターンごとにツールを宣言するので、Flowlight はそれを全部並べ、 モデルが実際に使ったものと、一度も触らなかったものを示します。
-
Codex の MCP サーバタブ。プロバイダ経由と記された sentry サーバ、その URL、承認は「しない」に設定、許可されたツールと提供するツールが表示されています
回線上では見えないものまで。エージェントがプロバイダ側に MCP サーバへの接続を任せると、その通信は Mac を通りません。 でも依頼そのものは通るので、サーバ、その URL、承認の設定、提供するツールはやはり表示されます。
@@ -459,7 +459,7 @@

監視しなくていい監視ツール

-
Flowlight での Claude Code の詳細。呼び出し回数と 1 件の失敗が付いたツールと MCP サーバ、許可リスト、そしてツール呼び出しタブに、失敗した git push、応答とリクエストを伴う paste.example への curl 送信、npm install、GitHub の issue、ドキュメント検索、ファイル読み取りが、それぞれの結果とともに並んでいます
1 つのエージェント、すべてのツール呼び出し。Claude Code が起動した git や curl、MCP サーバの通信は、Claude Code のものとして数えます。 HTTPS インスペクションをオンにすると、ツール呼び出しタブに、モデルが何を要求し、何が返り、各ツールがどんなリクエストを出したかが並びます。 @@ -469,10 +469,10 @@

監視しなくていい監視ツール

-
履歴ビュー。1 時間ごとの受信と送信の棒グラフ、アプリ・接続先・プロトコルのドーナツグラフが表示されています
履歴。秒から年までのズーム、3 つのグループ化、アプリが数百あっても読めるグラフ。
-
アラートビュー。エージェントの情報流出、メール、FTP、離席中、トラフィック急増のアラートが並んでいます
アラート。どれもアプリ、接続先、きっかけになった数値を示します。
@@ -588,7 +588,7 @@

Mac から何が出ていくのかを知る。

diff --git a/docs/ja/privacy/index.html b/docs/ja/privacy/index.html index 64d0cf72..3c7db9cc 100644 --- a/docs/ja/privacy/index.html +++ b/docs/ja/privacy/index.html @@ -187,7 +187,7 @@

連絡先

diff --git a/docs/ja/threat-model/index.html b/docs/ja/threat-model/index.html index 4ecc5abd..85db9d75 100644 --- a/docs/ja/threat-model/index.html +++ b/docs/ja/threat-model/index.html @@ -222,7 +222,7 @@

脆弱性を報告する

diff --git a/docs/ko/about/index.html b/docs/ko/about/index.html index c9a443f2..198b0756 100644 --- a/docs/ko/about/index.html +++ b/docs/ko/about/index.html @@ -153,7 +153,7 @@

감사

diff --git a/docs/ko/docs/index.html b/docs/ko/docs/index.html index 97e27060..82185075 100644 --- a/docs/ko/docs/index.html +++ b/docs/ko/docs/index.html @@ -76,7 +76,7 @@

문서

Flowlight 사용하기

-

첫 실행부터 에이전트 규칙 조정까지 전부. Flowlight 0.17.1, macOS 15 이상.

+

첫 실행부터 에이전트 규칙 조정까지 전부. Flowlight 0.17.2, macOS 15 이상.

diff --git a/docs/ko/index.html b/docs/ko/index.html index ce89f79d..70915bd5 100644 --- a/docs/ko/index.html +++ b/docs/ko/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

앱이 무엇을 하는지 봅니다.

brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+유니버설GPL-3.0텔레메트리 없음

+

v0.17.2macOS 15+유니버설GPL-3.0텔레메트리 없음

@@ -127,7 +127,7 @@

앱이 무엇을 하는지 봅니다.
-
Flowlight의 AI 활동 지도. 에이전트 카드는 귀속된 도구와 구성된 게이트웨이를 거치며, 관측된 magpie에서 Flowlight로의 경로가 LLM 서비스와 도메인으로 분기됩니다. 리본 너비는 기간 내 트래픽 양을 나타냅니다.

실제 AI 경로를 확인하세요. 에이전트, 귀속된 도구, 구성된 게이트웨이, Flowlight가 관측한 프록시 단계와 정확한 목적지를 표시합니다. 리본 너비는 선택한 기간의 수신량과 송신량 합계입니다. 데모 데이터로 표시했습니다.

@@ -135,7 +135,7 @@

앱이 무엇을 하는지 봅니다.
-
Flowlight의 AI 에이전트 뷰. Claude Code, Cursor, Codex, Python 스크립트가 각자의 AI 제공업체, 다른 곳으로 보낸 트래픽, 그리고 SMTP, SSH, FTP, 대용량 업로드, 원시 IP에 대한 위험 배지와 함께 나열되어 있습니다.

AI 에이전트 뷰: 각 에이전트의 모델 제공업체, 그리고 그 밖에 통신한 모든 곳. 데모 데이터로 표시했습니다.

@@ -177,17 +177,17 @@

AI 에이전트

에이전트가 모델을 부르는 것 말고 무엇

기록

다 어디로 갔나? 초에서 연까지, 앱·목적지·IP로 묶어 차트와 CSV로.

⌘3
-

알림

무엇이 이상했나? 목적지와 임계값까지 밝히는, 설명되는 앱별 알림.

⌘4
+

알림

무엇이 이상했나? 목적지와 임계값까지 밝히는, 설명되는 앱별 알림.

⌘5
-

규칙

무엇을 거부했고, 실제로 막히고 있나? 모든 규칙과 각 규칙이 막은 것, 그리고 모든 판정의 기록.

⌘5
+

규칙

무엇을 거부했고, 실제로 막히고 있나? 모든 규칙과 각 규칙이 막은 것, 그리고 모든 판정의 기록.

⌘8

질문

평소 쓰는 말로 묻고 기록에서 답을 받습니다. 실행된 질의는 아래에 전부 표시됩니다.

⌘6
-

기기

Bluetooth, USB, 카메라: 무엇이 페어링, 연결 또는 사용 중이며 언제 바뀌었나. 직접 켜기 전까지는 끔.

⌘8
+

기기

Bluetooth, USB, 카메라: 무엇이 페어링, 연결 또는 사용 중이며 언제 바뀌었나. 직접 켜기 전까지는 끔.

⌘9

검사

선택 사항. 에이전트가 실제로 무엇을 보냈고, 어떤 도구 호출이 그렇게 했나? 복호화된 요청, 도구 호출, 결과.

⌘7
-

연결

무엇이 통신하나? 앱 트래픽과 입증된 AI 에이전트 경로를 확대 가능한 Sankey 지도와 동일한 내용의 목록으로 보여 줍니다.

+

연결

무엇이 통신하나? 앱 트래픽과 입증된 AI 에이전트 경로를 확대 가능한 Sankey 지도와 동일한 내용의 목록으로 보여 줍니다.

⌘4 @@ -405,16 +405,16 @@

도구 호출과 네트워크 요청을 잇습니다

검사 대상인 터미널에서 에이전트를 실행하면 에이전트와 그 도구의 지원되는 HTTP 트래픽이 복호화되고, 모델이 요청한 도구 호출과 되돌아간 결과가 함께 보입니다.

-
Flowlight의 검사 뷰: 복호화된 Claude Code 요청과 각 요청의 도구 호출 목록, 그리고 curl이 paste.example로 올린 업로드의 상세 내용. 그 업로드를 실행한 Bash 도구 호출과 요청 본문에 담긴 메모가 함께 보입니다
내 메모는 어디로 갔나? curl이 paste.example로 올린 업로드를, 모델이 요청한 Bash 명령까지 거슬러 올라가 보낸 본문과 함께.
-
Claude Code의 도구 탭: Bash, Read와 MCP 도구 두 개가 설명, 그리고 모델이 각각을 몇 번 호출했는지와 함께 나열되어 있습니다
에이전트가 모델에게 내주는 모든 도구. 에이전트는 매 턴마다 도구를 선언하므로 Flowlight는 그것을 전부 나열하고, 모델이 실제로 쓴 것과 한 번도 건드리지 않은 것을 구분해 보여줍니다.
-
Codex의 MCP 서버 탭: 제공업체 경유로 표시된 sentry 서버, 그 URL, 승인은 사용 안 함, 허용된 도구, 그리고 서버가 제공하는 도구들
회선에서는 보이지 않는 것까지. 에이전트가 제공업체에게 MCP 서버로 연결해 달라고 하면 그 트래픽은 내 Mac을 거치지 않습니다. 하지만 요청은 거치므로 서버와 URL, 승인 설정, 제공하는 도구는 그대로 드러납니다.
@@ -460,7 +460,7 @@

감시하지 않아도 되는 감시 도구

-
Flowlight에 표시된 Claude Code 상세: 호출 횟수와 실패 하나가 붙은 도구와 MCP 서버, 허용 목록, 그리고 실패한 git push, 응답과 요청이 함께 있는 paste.example로의 curl 업로드, npm install, GitHub 이슈, 문서 검색, 파일 읽기가 각각 결과와 함께 나열된 도구 호출 탭
에이전트 하나, 도구 호출 전부. Claude Code가 띄운 git과 curl, MCP 서버의 트래픽은 Claude Code의 것으로 집계됩니다. HTTPS 검사를 켜면 도구 호출 탭에서 모델이 무엇을 요청했고 무엇이 돌아왔으며 각 도구가 어떤 요청을 @@ -470,10 +470,10 @@

감시하지 않아도 되는 감시 도구

-
시간별 수신·송신 막대와 앱, 목적지, 프로토콜 도넛 차트가 있는 기록 뷰
기록. 초에서 연까지의 확대·축소, 세 가지 묶음, 앱이 수백 개여도 읽히는 차트.
-
에이전트 유출, 이메일, FTP, 자리 비움, 트래픽 급증 알림이 나열된 알림 뷰
알림. 하나하나가 앱과 목적지, 그리고 기준을 넘긴 수치를 밝힙니다.
@@ -589,7 +589,7 @@

내 Mac에서 무엇이 나가는지 아세요.

diff --git a/docs/ko/privacy/index.html b/docs/ko/privacy/index.html index dd2da822..51e750fc 100644 --- a/docs/ko/privacy/index.html +++ b/docs/ko/privacy/index.html @@ -190,7 +190,7 @@

문의

diff --git a/docs/ko/threat-model/index.html b/docs/ko/threat-model/index.html index 65e301f3..67604aec 100644 --- a/docs/ko/threat-model/index.html +++ b/docs/ko/threat-model/index.html @@ -221,7 +221,7 @@

취약점 신고하기

diff --git a/docs/llms-full.txt b/docs/llms-full.txt index 6e553fe8..17b95e71 100644 --- a/docs/llms-full.txt +++ b/docs/llms-full.txt @@ -62,7 +62,7 @@ Documentation Using Flowlight - Everything from the first launch to tuning the agent rules. Flowlight 0.17.1, macOS 15 or later. + Everything from the first launch to tuning the agent rules. Flowlight 0.17.2, macOS 15 or later. On this page @@ -155,23 +155,23 @@ open build/Build/Products/Release/Flowlight.app History⌘3Where traffic went, from a 15-minute preset through all retained history. Group by App, Destination or IP; switch to Charts or Worth a look; export CSV. - Connections—A stable map of apps and their exact destinations, with weighted paths, moving direction markers, connection counts, and an equivalent list. + Connections⌘4A stable map of apps and their exact destinations, with weighted paths, moving direction markers, connection counts, and an equivalent list. - Alerts⌘4Everything that looked unusual, with the app, the destination and the number that tripped the rule. - - Rules⌘5Every allowlist and refusal you have set, what each one covers, and what it has actually stopped. + Alerts⌘5Everything that looked unusual, with the app, the destination and the number that tripped the rule. Ask⌘6Questions about your own traffic in plain language, answered from the recorded history by a local or a hosted model. Inspect⌘7Optional: decrypted requests from the agents you route through Flowlight, and the tool calls behind them. Search reaches into request and response bodies. - Devices⌘8Off until you turn it on: camera activity, Bluetooth, USB and external storage. + Rules⌘8Every allowlist and refusal you have set, what each one covers, and what it has actually stopped. + + Devices⌘9Off until you turn it on: camera activity, Bluetooth, USB and external storage. - Coverage⌘9What Flowlight cannot account for — per app, whether its traffic was seen, named, and readable. + Coverage⌘0What Flowlight cannot account for — per app, whether its traffic was seen, named, and readable. - Capture⌘0Which engine is recording, the extension's state, hostname learning, and where the database lives. + Capture—Which engine is recording, the extension's state, hostname learning, and where the database lives. - The shortcuts are the sidebar's order, so ⌘0 is the tenth item rather than a skipped position. + The shortcuts follow the sidebar's visible order: ⌘0 is the tenth item, and an eleventh remains available without an invented key. Live, the screen Flowlight opens on. In History, choose 15 min, 1h, 6h, 1d, 1w, 1 mo, 6 mo, 1y, or All. Hover-only bars open a cursor-following, scrollable card with the bucket totals and contributing apps; they never change the selected range. The navigator below the chart starts with Nearby context and can switch to All history: drag the brush to pan the selected window, or drag either edge to resize it. Double-click any breakdown row to narrow History to it. @@ -304,7 +304,7 @@ open build/Build/Products/Release/Flowlight.app Apple's own apps are left out by default. macOS contacts Apple constantly — Software Update, iCloud, push, time, Maps tiles — on hosts and ports that are new the first time they appear, and listing all of it buries the one - line worth reading. Turn it off in Settings › Alerts if you want them. Either way the traffic is still + line worth reading. Turn it off in Settings › Detection › Rules if you want them. Either way the traffic is still recorded, still appears in Live, History and Ask, and is still subject to every rule, guardrail and allowlist: the setting decides what is listed, never what is allowed. @@ -920,7 +920,7 @@ Understand your AI agents. brew install --cask xinbetween/tap/flowlightCopy - v0.17.1macOS 15+UniversalGPL-3.0No telemetry + v0.17.2macOS 15+UniversalGPL-3.0No telemetry connectionslive @@ -1001,11 +1001,11 @@ Where did it all go? From 15 minutes through all history, grouped by app, destin Alerts What looked wrong? Explainable, per-app alerts with the destination and the threshold. -⌘4 +⌘5 Rules What have I refused, and is it happening? Every rule, what each has blocked, and a feed of every decision. -⌘5 +⌘8 Ask Questions in plain language, answered from the history — with every query it ran listed underneath. @@ -1013,7 +1013,7 @@ Questions in plain language, answered from the history — with every query it r Devices Bluetooth, USB, and cameras: what's paired, what's attached or active, and when that changed. Off until you turn it on. -⌘8 +⌘9 Inspect Optional. What did the agent actually send, and which tool call made it? Decrypted requests, tool calls, results. @@ -1021,6 +1021,7 @@ Optional. What did the agent actually send, and which tool call made it? Decrypt Connections What is communicating? A zoomable Sankey map for app traffic and proved AI-agent paths, with exact list parity. +⌘4 Capture @@ -1663,9 +1664,22 @@ Releases Downloads, checksums and full notes for each version are on GitHub Releases. - 0.17.1 + 0.17.2 November 4, 2026Latest + Keep filtered evidence unmistakable. An active Focus now stays visible above every destination with its exact scope and one-click editing, while sidebar shortcuts follow the order shown on screen. + + Make warning notifications respond immediately. Turning warnings on now requests macOS authorization in the same action, reports whether access is active, not requested, or denied, and opens System Settings when recovery is needed. + + Stay ready for the next macOS. Live chart, table, rate, and source state now publish as one coherent snapshot, while sidebar selection waits for AppKit's callback to finish, removing a reentrant delegate operation that macOS warns will become an assertion. + + Test the exact commit a review names. Pull-request CI and CodeQL explicitly check out the head SHA, a deny-first rename-aware classifier fails unknown and release inputs closed to the full app route, and one stable gate records the tested tree and app-input fingerprint. + + Keep website work independent from app releases. Explicitly allowlisted website-only changes require no application version bump, while project, packaging, screenshot, signed-catalog, workflow, and other release inputs can never skip macOS verification. + + 0.17.1 +November 4, 2026 + Keep every public screenshot current. All ten website images now come from the same 0.17.1 demo build, consistently show History and Connections in the sidebar, and use History throughout linked actions and guidance. Review the Store with the same product users receive. A complete 2880×1800 Mac App Store screenshot set is captured from that exact build, title-checked screen by screen, and retained with the release for App Store Connect. diff --git a/docs/llms.txt b/docs/llms.txt index 86251b79..f03cca17 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -1,6 +1,6 @@ # Flowlight -> Free, open-source (GPL-3.0) application-aware network monitor for macOS, with focused visibility into AI agents. It attributes observed TCP and UDP activity to the application that made it and records the destination, protocol and byte counts, keeping local history from second to year. Recognized AI agents are listed by name along with the tools and MCP servers they start, under per-agent allowlists. It can also refuse, once asked: a rule blocks an application, a destination or a URL for as long as you specify, and a guardrail withholds a tool from an agent before its model is offered it. Runs on macOS 15 or later; capture is by a sampler or a Network Extension. Current version: 0.17.1. +> Free, open-source (GPL-3.0) application-aware network monitor for macOS, with focused visibility into AI agents. It attributes observed TCP and UDP activity to the application that made it and records the destination, protocol and byte counts, keeping local history from second to year. Recognized AI agents are listed by name along with the tools and MCP servers they start, under per-agent allowlists. It can also refuse, once asked: a rule blocks an application, a destination or a URL for as long as you specify, and a guardrail withholds a tool from an agent before its model is offered it. Runs on macOS 15 or later; capture is by a sampler or a Network Extension. Current version: 0.17.2. - [Download Flowlight.dmg](https://github.com/xinbetween/flowlight/releases/latest/download/Flowlight.dmg) - [Source code](https://github.com/xinbetween/flowlight) diff --git a/docs/plugins/index.html b/docs/plugins/index.html index 6f00fda9..79654d16 100644 --- a/docs/plugins/index.html +++ b/docs/plugins/index.html @@ -212,7 +212,7 @@

Review checklist

diff --git a/docs/privacy/index.html b/docs/privacy/index.html index 95b5aa02..62d2b4c9 100644 --- a/docs/privacy/index.html +++ b/docs/privacy/index.html @@ -196,7 +196,7 @@

Contact

diff --git a/docs/pt-PT/about/index.html b/docs/pt-PT/about/index.html index fb93fc5a..df05dc0e 100644 --- a/docs/pt-PT/about/index.html +++ b/docs/pt-PT/about/index.html @@ -152,7 +152,7 @@

Agradecimentos

diff --git a/docs/pt-PT/docs/index.html b/docs/pt-PT/docs/index.html index 7e8e0b4d..a8248565 100644 --- a/docs/pt-PT/docs/index.html +++ b/docs/pt-PT/docs/index.html @@ -76,7 +76,7 @@

Documentação

Usar o Flowlight

-

Tudo, da primeira abertura ao ajuste das regras dos agentes. Flowlight 0.17.1, macOS 15 ou posterior.

+

Tudo, da primeira abertura ao ajuste das regras dos agentes. Flowlight 0.17.2, macOS 15 ou posterior.

diff --git a/docs/pt-PT/index.html b/docs/pt-PT/index.html index 4a893d57..80504841 100644 --- a/docs/pt-PT/index.html +++ b/docs/pt-PT/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

Veja a atividade de rede das suas apps.

brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+UniversalGPL-3.0Sem telemetria

+

v0.17.2macOS 15+UniversalGPL-3.0Sem telemetria

@@ -127,7 +127,7 @@

Veja a atividade de rede das suas apps.
-
O mapa de atividade de IA do Flowlight. Os cartões de agentes passam por ferramentas atribuídas e gateways configurados; a rota observada do magpie para o Flowlight ramifica-se depois para serviços LLM e domínios. A largura das faixas mostra o tráfego do período.

Veja a rota de IA real: agentes, ferramentas atribuídas, gateways configurados, a etapa de proxy observada pelo Flowlight e destinos exatos. A largura mostra o total recebido e enviado no período selecionado. Com dados de demonstração.

@@ -135,7 +135,7 @@

Veja a atividade de rede das suas apps.
-
A vista Agentes de IA do Flowlight. O Claude Code, o Cursor, o Codex e um script de Python aparecem com os respetivos fornecedores de IA, o tráfego enviado para outros sítios e indicadores de risco para SMTP, SSH, FTP, um envio grande e um IP direto.

A vista Agentes de IA: o fornecedor do modelo de cada agente e tudo o mais com que falou. Mostrada com dados de demonstração.

@@ -177,17 +177,17 @@

Agentes de IA

O que fazem os meus agentes além de chamar o modelo? F

Histórico

Para onde foi tudo? Do segundo ao ano, agrupado por app, destino ou IP, com gráficos e CSV.

⌘3
-

Alertas

O que pareceu errado? Alertas por app, explicáveis, com o destino e o limiar.

⌘4
+

Alertas

O que pareceu errado? Alertas por app, explicáveis, com o destino e o limiar.

⌘5
-

Regras

O que recusei e está a acontecer? Todas as regras, o que cada uma bloqueou e um fluxo de todas as decisões.

⌘5
+

Regras

O que recusei e está a acontecer? Todas as regras, o que cada uma bloqueou e um fluxo de todas as decisões.

⌘8

Perguntar

Perguntas em linguagem comum, respondidas a partir do histórico — com todas as consultas que fez listadas abaixo.

⌘6
-

Dispositivos

Bluetooth, USB e câmaras: o que está emparelhado, ligado ou ativo e quando isso mudou. Desativado até o ativar.

⌘8
+

Dispositivos

Bluetooth, USB e câmaras: o que está emparelhado, ligado ou ativo e quando isso mudou. Desativado até o ativar.

⌘9

Inspecionar

Opcional. O que é que o agente enviou de facto, e que chamada de ferramenta o fez? Pedidos desencriptados, chamadas de ferramentas, resultados.

⌘7
-

Ligações

O que está a comunicar? Um mapa Sankey ampliável do tráfego das apps e dos percursos comprovados dos agentes de IA, com uma lista exata equivalente.

+

Ligações

O que está a comunicar? Um mapa Sankey ampliável do tráfego das apps e dos percursos comprovados dos agentes de IA, com uma lista exata equivalente.

⌘4 @@ -405,16 +405,16 @@

Relacione as chamadas de ferramentas suportadas com os pedidos de rede

seu Mac. Inicie um agente a partir de um Terminal inspecionado e o tráfego HTTP suportado do agente e das suas ferramentas é desencriptado, com as chamadas de ferramentas que o modelo pediu e os resultados que voltaram.

-
A vista Inspecionar do Flowlight: uma lista de pedidos desencriptados do Claude Code com as respetivas chamadas de ferramentas e o detalhe do envio do curl para paste.example, feito pela chamada da ferramenta Bash que o executou, com as notas enviadas no corpo do pedido
Para onde foram as minhas notas? O envio do curl para paste.example, seguido até ao comando Bash que o modelo pediu, com o corpo que enviou.
-
O separador Ferramentas do Claude Code: Bash, Read e duas ferramentas MCP com descrições e a frequência com que o modelo chamou cada uma
Todas as ferramentas que um agente oferece ao modelo. Os agentes declaram as suas ferramentas em cada turno, por isso o Flowlight lista-as todas, com as que o modelo usou de facto e as que nunca tocou.
-
O separador Servidores MCP do Codex: um servidor sentry marcado como via fornecedor, o seu URL, a aprovação definida como nunca, as ferramentas permitidas e as ferramentas que oferece
Incluindo as que não se veem na rede. Quando um agente pede ao fornecedor que se ligue a um servidor MCP, esse tráfego nunca passa pelo seu Mac. O pedido passa, por isso o servidor, o seu URL, a sua definição de aprovação e as suas ferramentas aparecem mesmo assim.
@@ -460,7 +460,7 @@

Um monitor que não tem de monitorizar

-
O detalhe do Claude Code no Flowlight: ferramentas e servidores MCP com contagens de chamadas e uma falha, uma lista de permissões e o separador Chamadas de ferramentas com um git push falhado, um envio do curl para paste.example com a resposta e o pedido, um npm install, um problema no GitHub, uma pesquisa na documentação e uma leitura de ficheiro, cada um com o seu resultado
Um agente, todas as chamadas de ferramentas. O tráfego do git, do curl e dos servidores MCP que o Claude Code iniciou conta como tráfego do Claude Code. Com a inspeção HTTPS ativada, o separador Chamadas de ferramentas mostra o que o modelo pediu, o que voltou e os pedidos que cada ferramenta fez: @@ -470,10 +470,10 @@

Um monitor que não tem de monitorizar

-
A vista Histórico com barras horárias de dados recebidos e enviados e gráficos circulares de apps, destinos e protocolos
Histórico. Zoom do segundo ao ano, três agrupamentos, gráficos que continuam legíveis com centenas de apps.
-
A vista Alertas a listar alertas de exfiltração por um agente, de e-mail, de FTP, de atividade durante a ausência e de picos de tráfego
Alertas. Cada um nomeia a app, o destino e o número que o disparou.
@@ -589,7 +589,7 @@

Saiba o que sai do seu Mac.

diff --git a/docs/pt-PT/privacy/index.html b/docs/pt-PT/privacy/index.html index 35de0946..8d6e7efd 100644 --- a/docs/pt-PT/privacy/index.html +++ b/docs/pt-PT/privacy/index.html @@ -189,7 +189,7 @@

Contacto

diff --git a/docs/pt-PT/threat-model/index.html b/docs/pt-PT/threat-model/index.html index 2833bbb9..facee204 100644 --- a/docs/pt-PT/threat-model/index.html +++ b/docs/pt-PT/threat-model/index.html @@ -222,7 +222,7 @@

Comunicar uma vulnerabilidade

diff --git a/docs/releases/index.html b/docs/releases/index.html index 78a6061b..4b343dbd 100644 --- a/docs/releases/index.html +++ b/docs/releases/index.html @@ -61,7 +61,18 @@

What's new

-

0.17.1

Latest
+

0.17.2

Latest
+
    +
  • Keep filtered evidence unmistakable. An active Focus now stays visible above every destination with its exact scope and one-click editing, while sidebar shortcuts follow the order shown on screen.
  • +
  • Make warning notifications respond immediately. Turning warnings on now requests macOS authorization in the same action, reports whether access is active, not requested, or denied, and opens System Settings when recovery is needed.
  • +
  • Stay ready for the next macOS. Live chart, table, rate, and source state now publish as one coherent snapshot, while sidebar selection waits for AppKit's callback to finish, removing a reentrant delegate operation that macOS warns will become an assertion.
  • +
  • Test the exact commit a review names. Pull-request CI and CodeQL explicitly check out the head SHA, a deny-first rename-aware classifier fails unknown and release inputs closed to the full app route, and one stable gate records the tested tree and app-input fingerprint.
  • +
  • Keep website work independent from app releases. Explicitly allowlisted website-only changes require no application version bump, while project, packaging, screenshot, signed-catalog, workflow, and other release inputs can never skip macOS verification.
  • +
+
+ +
+

0.17.1

  • Keep every public screenshot current. All ten website images now come from the same 0.17.1 demo build, consistently show History and Connections in the sidebar, and use History throughout linked actions and guidance.
  • Review the Store with the same product users receive. A complete 2880×1800 Mac App Store screenshot set is captured from that exact build, title-checked screen by screen, and retained with the release for App Store Connect.
  • @@ -1571,7 +1582,7 @@

    What's new

diff --git a/docs/threat-model/index.html b/docs/threat-model/index.html index 36805d5e..3b6fbe01 100644 --- a/docs/threat-model/index.html +++ b/docs/threat-model/index.html @@ -231,7 +231,7 @@

Reporting a vulnerability

diff --git a/docs/zh-Hans/about/index.html b/docs/zh-Hans/about/index.html index 374b11d0..87ce0972 100644 --- a/docs/zh-Hans/about/index.html +++ b/docs/zh-Hans/about/index.html @@ -152,7 +152,7 @@

致谢

diff --git a/docs/zh-Hans/docs/index.html b/docs/zh-Hans/docs/index.html index 88311d67..7d09340e 100644 --- a/docs/zh-Hans/docs/index.html +++ b/docs/zh-Hans/docs/index.html @@ -76,7 +76,7 @@

文档

使用 Flowlight

-

从第一次启动到调整代理规则,需要的都在这里。Flowlight 0.17.1,macOS 15 或更高版本。

+

从第一次启动到调整代理规则,需要的都在这里。Flowlight 0.17.2,macOS 15 或更高版本。

diff --git a/docs/zh-Hans/index.html b/docs/zh-Hans/index.html index 7cf2009b..98f7e540 100644 --- a/docs/zh-Hans/index.html +++ b/docs/zh-Hans/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

看清应用的网络活动。

brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+通用架构GPL-3.0无遥测

+

v0.17.2macOS 15+通用架构GPL-3.0无遥测

@@ -127,7 +127,7 @@

看清应用的网络活动。
-
Flowlight 的 AI 活动图。代理卡片经过已归属工具和已配置网关;观测到的 magpie 到 Flowlight 路由随后分支至 LLM 服务和域名。带状线宽度表示所选时段的流量。

查看真实 AI 路由:代理、已归属工具、已配置网关、Flowlight 观测到的代理阶段和精确目标。带状线宽度表示所选时段接收与发送流量的总和。图中为演示数据。

@@ -135,7 +135,7 @@

看清应用的网络活动。
-
Flowlight 的 AI 代理视图。Claude Code、Cursor、Codex 和一个 Python 脚本逐行列出,显示各自的 AI 提供方、发往别处的流量,以及 SMTP、SSH、FTP、大量上传和裸 IP 的风险标记。

AI 代理视图:每个代理的模型提供方,以及它联系过的其他一切。图中为演示数据。

@@ -177,17 +177,17 @@

AI 代理

我的代理除了调用模型还在做什么?提供方

历史

流量究竟去了哪?从秒到年,按应用、目标或 IP 分组,配图表与 CSV。

⌘3
-

警报

哪里不对?逐应用、讲得清道理的警报,带上目标和阈值。

⌘4
+

警报

哪里不对?逐应用、讲得清道理的警报,带上目标和阈值。

⌘5
-

规则

我拒绝过什么,真的生效了吗?每条规则、各自阻止了什么,以及每次判定的流水。

⌘5
+

规则

我拒绝过什么,真的生效了吗?每条规则、各自阻止了什么,以及每次判定的流水。

⌘8

提问

用日常语言提问,从历史数据里作答——下方列出它执行过的每一条查询。

⌘6
-

设备

蓝牙、USB 和摄像头:配对了什么、接入或启用了什么、什么时候变的。默认关闭,你开了才记录。

⌘8
+

设备

蓝牙、USB 和摄像头:配对了什么、接入或启用了什么、什么时候变的。默认关闭,你开了才记录。

⌘9

检查

可选。代理究竟发出了什么,是哪次工具调用引起的?解密后的请求、工具调用和结果。

⌘7
-

连接

谁在通信?用可缩放的 Sankey 图展示应用流量和已证实的 AI 代理路径,并提供内容完全一致的列表。

+

连接

谁在通信?用可缩放的 Sankey 图展示应用流量和已证实的 AI 代理路径,并提供内容完全一致的列表。

⌘4 @@ -402,16 +402,16 @@

把受支持的工具调用与网络请求对上

默认关闭。打开后,Flowlight 会成为一个本地代理,使用在你 Mac 上生成的专属证书颁发机构。 从受检查的终端启动代理,代理及其工具的受支持 HTTP 流量就会被解密,并附上模型请求的工具调用和返回的结果。

-
Flowlight 的检查视图:一列已解密的 Claude Code 请求及其工具调用,以及 curl 向 paste.example 上传的详情——由运行它的那次 Bash 工具调用发起,请求体里正是上传的笔记
我的笔记去哪了?curl 向 paste.example 的上传,一路追到模型要求执行的那条 Bash 命令, 连它发出的请求体一起。
-
Claude Code 的工具标签页:Bash、Read 和两个 MCP 工具,附带说明以及模型各自调用了多少次
代理提供给模型的每一个工具。代理每一轮都会声明自己的工具,所以 Flowlight 把它们全部列出, 并区分模型真正用过的和从未碰过的。
-
Codex 的 MCP 服务器标签页:一个标为“经由提供方”的 sentry 服务器,以及它的 URL、设为“从不”的审批、允许的工具和它提供的工具
连线路上看不到的那些也算。当代理请求提供方去连接某个 MCP 服务器时,那段流量根本不会经过你的 Mac。 但它的请求会,所以这个服务器、它的 URL、它的审批设置和它的工具依然会出现。
@@ -457,7 +457,7 @@

一个不用你盯着的监控工具

-
Flowlight 里 Claude Code 的详情:带调用次数和一次失败的工具与 MCP 服务器、一个允许列表,以及工具调用标签页,里面列出一次失败的 git push、一次 curl 向 paste.example 的上传及其响应和请求、npm install、一个 GitHub issue、一次文档搜索和一次文件读取,每项都带结果
一个代理,每一次工具调用。Claude Code 启动的 git、curl 和 MCP 服务器产生的流量都算作 Claude Code 的。 打开 HTTPS 检查后,工具调用标签页会显示模型要求了什么、返回了什么,以及每个工具发出的请求: @@ -467,10 +467,10 @@

一个不用你盯着的监控工具

-
历史视图,含每小时接收与发送的柱状图,以及应用、目标和协议的环形图
历史。从秒到年的缩放、三种分组方式,几百个应用也读得清的图表。
-
警报视图,列出代理外泄、邮件、FTP、你离开时活动和流量突增等警报
警报。每一条都点明应用、目标和触发它的那个数字。
@@ -586,7 +586,7 @@

知道什么离开了你的 Mac。

diff --git a/docs/zh-Hans/privacy/index.html b/docs/zh-Hans/privacy/index.html index 4b56be4f..c3aa2b1c 100644 --- a/docs/zh-Hans/privacy/index.html +++ b/docs/zh-Hans/privacy/index.html @@ -187,7 +187,7 @@

联系方式

diff --git a/docs/zh-Hans/threat-model/index.html b/docs/zh-Hans/threat-model/index.html index 3f0a5e1c..d4cfdf9b 100644 --- a/docs/zh-Hans/threat-model/index.html +++ b/docs/zh-Hans/threat-model/index.html @@ -210,7 +210,7 @@

报告漏洞

diff --git a/docs/zh-Hant/about/index.html b/docs/zh-Hant/about/index.html index 73bbfd0c..6e6930e2 100644 --- a/docs/zh-Hant/about/index.html +++ b/docs/zh-Hant/about/index.html @@ -152,7 +152,7 @@

致謝

diff --git a/docs/zh-Hant/docs/index.html b/docs/zh-Hant/docs/index.html index 389ff316..32d0e1b4 100644 --- a/docs/zh-Hant/docs/index.html +++ b/docs/zh-Hant/docs/index.html @@ -76,7 +76,7 @@

說明文件

使用 Flowlight

-

從第一次啟動到調整代理規則,全都在這裡。Flowlight 0.17.1,macOS 15 或以上版本。

+

從第一次啟動到調整代理規則,全都在這裡。Flowlight 0.17.2,macOS 15 或以上版本。

diff --git a/docs/zh-Hant/index.html b/docs/zh-Hant/index.html index 61c6746c..688de481 100644 --- a/docs/zh-Hant/index.html +++ b/docs/zh-Hant/index.html @@ -48,7 +48,7 @@ - + @@ -97,7 +97,7 @@

看見每個 App 的網路活動。
brew install --cask xinbetween/tap/flowlight

-

v0.17.1macOS 15+通用架構GPL-3.0無遙測

+

v0.17.2macOS 15+通用架構GPL-3.0無遙測

@@ -127,7 +127,7 @@

看見每個 App 的網路活動。
-
Flowlight 的 AI 活動圖。代理卡片經過已歸屬工具和已設定閘道;觀測到的 magpie 至 Flowlight 路由隨後分支至 LLM 服務和網域。帶狀線寬度表示所選時段的流量。

查看真實 AI 路由:代理、已歸屬工具、已設定閘道、Flowlight 觀測到的代理階段和精確目的地。帶狀線寬度表示所選時段接收與傳送流量的總和。圖中為示範資料。

@@ -135,7 +135,7 @@

看見每個 App 的網路活動。
-
Flowlight 的「AI 代理」畫面。Claude Code、Cursor、Codex 和一個 Python 指令碼列在其中,顯示各自的 AI 供應商、傳往其他地方的流量,以及 SMTP、SSH、FTP、大量上傳和裸 IP 的風險標記。

「AI 代理」畫面:每個代理的模型供應商,以及它連線過的其他所有目標。圖中為示範資料。

@@ -177,17 +177,17 @@

AI 代理

我的代理除了呼叫模型,還在做什麼?供應

歷史

流量都到哪去了?從秒到年,依 App、目標或 IP 分組,附圖表與 CSV。

⌘3
-

警示

哪裡看起來不對?每個 App 都有說得清楚的警示,附上目標和閾值。

⌘4
+

警示

哪裡看起來不對?每個 App 都有說得清楚的警示,附上目標和閾值。

⌘5
-

規則

我拒絕了什麼,真的有在擋嗎?每一條規則、各自封鎖過什麼,以及每一次決定的紀錄。

⌘5
+

規則

我拒絕了什麼,真的有在擋嗎?每一條規則、各自封鎖過什麼,以及每一次決定的紀錄。

⌘8

提問

用日常語言提問,從歷史記錄裡得到答案 — 下方還列出它跑過的每一條查詢。

⌘6
-

裝置

藍牙、USB 和攝影機:配對了什麼、接上或啟用了什麼,以及什麼時候變動的。要等你開啟才會作用。

⌘8
+

裝置

藍牙、USB 和攝影機:配對了什麼、接上或啟用了什麼,以及什麼時候變動的。要等你開啟才會作用。

⌘9

檢查

選用功能。代理實際送出了什麼,又是哪一次工具呼叫造成的?解密後的請求、工具呼叫、結果。

⌘7
-

連線

誰在通訊?用可縮放的 Sankey 圖顯示 App 流量和已證實的 AI 代理路徑,並提供內容完全一致的列表。

+

連線

誰在通訊?用可縮放的 Sankey 圖顯示 App 流量和已證實的 AI 代理路徑,並提供內容完全一致的列表。

⌘4 @@ -403,16 +403,16 @@

把支援的工具呼叫和網路請求對起來

單位。從受檢查的「終端機」啟動代理,它和它的工具所產生的支援 HTTP 流量就會被解密,連同模型要求的 工具呼叫和回傳的結果。

-
Flowlight 的「檢查」畫面:一份解密後的 Claude Code 請求列表及其工具呼叫,以及 curl 上傳到 paste.example 的詳細內容 — 那次上傳由執行它的 Bash 工具呼叫發出,請求內文中還有上傳的筆記
我的筆記去哪了? curl 上傳到 paste.example,追溯到模型要求執行的 Bash 指令,連同它 送出的內文。
-
Claude Code 的「工具」標籤頁:Bash、Read 和兩個 MCP 工具,附上說明以及模型各呼叫了幾次
代理提供給模型的每一個工具。 代理每一輪都會宣告自己的工具,所以 Flowlight 會全部列出來,包含模型 真正用過的,以及完全沒碰過的。
-
Codex 的「MCP 伺服器」標籤頁:一個標示為「透過供應商」的 sentry 伺服器,包含它的 URL、設為永不核准的核准設定、允許的工具,以及它提供的工具
連你在線路上看不到的也算。 當代理請供應商去連接某個 MCP 伺服器,那段流量 根本不會經過你的 Mac。但代理的請求會,所以那個伺服器、它的 URL、它的核准設定和它的工具仍然會出現。
@@ -458,7 +458,7 @@

一個不用你盯著的監控工具

-
Flowlight 中 Claude Code 的詳細資料:工具與 MCP 伺服器及其呼叫次數和一次失敗、一份允許清單,以及「工具呼叫」標籤頁 — 其中列出一次失敗的 git push、一次 curl 上傳到 paste.example 及其回應與請求、npm install、一個 GitHub issue、一次說明文件搜尋和一次檔案讀取,每一項都附上結果
一個代理,每一次工具呼叫。 Claude Code 啟動的 git、curl 和 MCP 伺服器所產生的流量,都算成 Claude Code 的。 開啟 HTTPS 檢查後,工具呼叫標籤頁會顯示模型要求了什麼、回來了什麼,以及各個工具發出的請求: @@ -468,10 +468,10 @@

一個不用你盯著的監控工具

-
「歷史」畫面:每小時接收與傳送的長條圖,以及 App、目標和協定的環圈圖
歷史。 從秒到年的縮放、三種分組方式,即使有上百個 App,圖表依然看得清楚。
-
「警示」畫面:列出代理資料外洩、郵件、FTP、離開期間活動和流量尖峰等警示
警示。 每一則都指出 App、目標,以及觸發它的那個數字。
@@ -587,7 +587,7 @@

知道有什麼離開了你的 Mac。

diff --git a/docs/zh-Hant/privacy/index.html b/docs/zh-Hant/privacy/index.html index b2a0280b..efa04350 100644 --- a/docs/zh-Hant/privacy/index.html +++ b/docs/zh-Hant/privacy/index.html @@ -187,7 +187,7 @@

聯絡

diff --git a/docs/zh-Hant/threat-model/index.html b/docs/zh-Hant/threat-model/index.html index 76bfdadb..5b803482 100644 --- a/docs/zh-Hant/threat-model/index.html +++ b/docs/zh-Hant/threat-model/index.html @@ -211,7 +211,7 @@

回報漏洞

diff --git a/packaging/app-store/screenshots/macos/01-connections.png b/packaging/app-store/screenshots/macos/01-connections.png index e63fbf7b..c12748a3 100644 Binary files a/packaging/app-store/screenshots/macos/01-connections.png and b/packaging/app-store/screenshots/macos/01-connections.png differ diff --git a/packaging/app-store/screenshots/macos/02-ai-agents.png b/packaging/app-store/screenshots/macos/02-ai-agents.png index d66b43f6..738db710 100644 Binary files a/packaging/app-store/screenshots/macos/02-ai-agents.png and b/packaging/app-store/screenshots/macos/02-ai-agents.png differ diff --git a/packaging/app-store/screenshots/macos/03-history.png b/packaging/app-store/screenshots/macos/03-history.png index 5f327a70..4360b9ff 100644 Binary files a/packaging/app-store/screenshots/macos/03-history.png and b/packaging/app-store/screenshots/macos/03-history.png differ diff --git a/packaging/app-store/screenshots/macos/04-rules.png b/packaging/app-store/screenshots/macos/04-rules.png index 76a88ea3..4ae2578e 100644 Binary files a/packaging/app-store/screenshots/macos/04-rules.png and b/packaging/app-store/screenshots/macos/04-rules.png differ diff --git a/packaging/app-store/screenshots/macos/05-live.png b/packaging/app-store/screenshots/macos/05-live.png index 150c58e1..3f50b184 100644 Binary files a/packaging/app-store/screenshots/macos/05-live.png and b/packaging/app-store/screenshots/macos/05-live.png differ diff --git a/packaging/app-store/screenshots/macos/06-alerts.png b/packaging/app-store/screenshots/macos/06-alerts.png index fb729e4c..1ea33726 100644 Binary files a/packaging/app-store/screenshots/macos/06-alerts.png and b/packaging/app-store/screenshots/macos/06-alerts.png differ diff --git a/packaging/app-store/screenshots/macos/07-agent-detail.png b/packaging/app-store/screenshots/macos/07-agent-detail.png index 1abc4226..37171907 100644 Binary files a/packaging/app-store/screenshots/macos/07-agent-detail.png and b/packaging/app-store/screenshots/macos/07-agent-detail.png differ diff --git a/packaging/app-store/screenshots/macos/08-agent-tools.png b/packaging/app-store/screenshots/macos/08-agent-tools.png index c034c414..9ddf47c1 100644 Binary files a/packaging/app-store/screenshots/macos/08-agent-tools.png and b/packaging/app-store/screenshots/macos/08-agent-tools.png differ diff --git a/packaging/app-store/screenshots/macos/09-mcp-servers.png b/packaging/app-store/screenshots/macos/09-mcp-servers.png index 6f10360f..03d0944e 100644 Binary files a/packaging/app-store/screenshots/macos/09-mcp-servers.png and b/packaging/app-store/screenshots/macos/09-mcp-servers.png differ diff --git a/packaging/app-store/screenshots/macos/manifest.json b/packaging/app-store/screenshots/macos/manifest.json index 34ee9c67..2df1ccc6 100644 --- a/packaging/app-store/screenshots/macos/manifest.json +++ b/packaging/app-store/screenshots/macos/manifest.json @@ -3,56 +3,56 @@ "screenshots": { "01-connections.png": { "height": 1800, - "sha256": "b8c2265f4935d8b7cbf4d1cded01920b46cddd1b49bca7cab3b63a3900cf8b00", - "version": "0.17.1", + "sha256": "ba93c8fc487d13f5acfb61d132696a49a68cdc339b982ece11fe4b564aae1bf3", + "version": "0.17.2", "width": 2880 }, "02-ai-agents.png": { "height": 1800, - "sha256": "c4bef89303043f2711071a3d23f6de6a4777ed0ee67dbfbcdf473bcbdea5db8f", - "version": "0.17.1", + "sha256": "ae52b119de45ebe862d92d9688f6b50f908ebcf8373abd97215d47e9477c346a", + "version": "0.17.2", "width": 2880 }, "03-history.png": { "height": 1800, - "sha256": "91358f6f4dbb919e939ef47feaf24bdd6eb055dddf044873a15fab780099c98c", - "version": "0.17.1", + "sha256": "236460a16782b634d6ef1cdefa97d2ab2167c6013ac487269da063693133aadc", + "version": "0.17.2", "width": 2880 }, "04-rules.png": { "height": 1800, - "sha256": "1b7968afe707fd16ce6109a089e7630a1a744c43e4976bc2d15622964c26d669", - "version": "0.17.1", + "sha256": "268993cf96e2c7335e0762bb964ac9794e1875d0ac239ac57c493207176a0e7c", + "version": "0.17.2", "width": 2880 }, "05-live.png": { "height": 1800, - "sha256": "a22fb51ab087f96d15e71c07af1cbe931e26b17b168e16071144b138d63438ea", - "version": "0.17.1", + "sha256": "e4bfee31bd0aff7cdd16bf39dfaf15bf55873a6bcf6f36db50700be44533bc33", + "version": "0.17.2", "width": 2880 }, "06-alerts.png": { "height": 1800, - "sha256": "0e606b9df9be6bc761b3690954400c17165b3e71d3c0e7d725e1602ba8c2eca6", - "version": "0.17.1", + "sha256": "bb39827916cf5f014e4dbecb0309a4aa52eaec1471bfd70e1791ec80a9643cac", + "version": "0.17.2", "width": 2880 }, "07-agent-detail.png": { "height": 1800, - "sha256": "51a083b23cfed1770f8c5d0f217d115a3fe2a226002f8562ce78d099c1998824", - "version": "0.17.1", + "sha256": "03811822d64151a900e58917fa563f6f1b18e231ed48c48e65d036e7cb61fb9b", + "version": "0.17.2", "width": 2880 }, "08-agent-tools.png": { "height": 1800, - "sha256": "7c1829d409a867eb36f272ef8bf09402bc09bc537b2ddf865970dfd81304354f", - "version": "0.17.1", + "sha256": "74ad996c6426169003019fe46fa9ac9100173cc49b6556b182c389cc7634928c", + "version": "0.17.2", "width": 2880 }, "09-mcp-servers.png": { "height": 1800, - "sha256": "e2bbb4fdf6a2d4f782c4b2d3c70c55ed810f56f94539d89ff9e6c31559e6917d", - "version": "0.17.1", + "sha256": "33845e39815afb2a29c82b59f7a0b1f7662e438b727a3786ab2d83d419a01734", + "version": "0.17.2", "width": 2880 } } diff --git a/project.yml b/project.yml index aaa1644c..d2ede6bf 100644 --- a/project.yml +++ b/project.yml @@ -15,8 +15,8 @@ settings: DEVELOPMENT_TEAM: "" CODE_SIGN_STYLE: Automatic ENABLE_HARDENED_RUNTIME: YES - MARKETING_VERSION: "0.17.1" - CURRENT_PROJECT_VERSION: "75" + MARKETING_VERSION: "0.17.2" + CURRENT_PROJECT_VERSION: "76" configs: AppStore: DEVELOPMENT_TEAM: 38RJUJHKZS diff --git a/scripts/check_release_checks.py b/scripts/check_release_checks.py index 587e608c..057260b0 100644 --- a/scripts/check_release_checks.py +++ b/scripts/check_release_checks.py @@ -12,6 +12,7 @@ ("github-actions", "site"), ("github-actions", "test (oldest Xcode)"), ("github-actions", "test (newest Xcode)"), + ("github-actions", "Review / gate"), ("github-actions", "analyze (swift)"), ("github-actions", "analyze (python)"), ("github-actions", "analyze (actions)"), diff --git a/scripts/check_site.py b/scripts/check_site.py index b4012f85..fe3d60b2 100644 --- a/scripts/check_site.py +++ b/scripts/check_site.py @@ -41,7 +41,7 @@ IMG = re.compile(r']*src="([^"]*assets/screenshots/[^"]+)"([^>]*)>') WH = re.compile(r'\b(width|height)="(\d+)"') HELP_ANCHOR = re.compile(r'case \.(\w+): return "([\w-]+)"') -SIDEBAR = re.compile(r"enum SidebarItem[^{]*\{\s*case ([\w, ]+)") +SIDEBAR_GROUP = re.compile(r"case \.\w+: order = \[([^\]]*)\]") ROW = re.compile(r"(?:]*>)?([^<]+)(?:)?\u2318(.)") HOME_CARD = re.compile(r'
\u2318(.)
', re.S) H1 = re.compile(r"]") @@ -56,6 +56,18 @@ def version_key(text): return tuple(int(part) for part in text.split(".")) +def sidebar_order(source): + """Extract the authoritative grouped order used by SidebarItem.sidebarOrder.""" + start = source.find("var items: [SidebarItem]") + end = source.find("return order.filter", start) + if start < 0 or end < 0: + raise ValueError("could not find SidebarSection.items") + groups = SIDEBAR_GROUP.findall(source[start:end]) + if not groups: + raise ValueError("could not find the grouped sidebar order") + return [item for group in groups for item in re.findall(r"\.(\w+)", group)] + + def problems(): found = [] @@ -248,7 +260,7 @@ def entries(text): # 12. A shortcut the documentation gets wrong. The sidebar's order *is* the shortcut — ⌘1 to ⌘0 by # position — so inserting a screen silently renumbers every screen after it. The table said Inspect was # ⌘5 long after it had become ⌘7, and four screens had been added without ever reaching the table. - order = [c.strip() for c in SIDEBAR.search(nav).group(1).split(",") if c.strip()] + order = sidebar_order(nav) titles = dict(HELP_ANCHOR.findall(nav[nav.find("var englishTitle"):nav.find("var title")])) docs_text = (OUT / "docs/index.html").read_text() rows = {name.strip(): key for name, key in ROW.findall(docs_text)} diff --git a/scripts/classify_changes.py b/scripts/classify_changes.py new file mode 100644 index 00000000..a1b362bf --- /dev/null +++ b/scripts/classify_changes.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 +"""Classify a Git change without letting an unknown path skip app verification. + +The website-only route is deliberately an allowlist. Every path Git reports for a +rename or copy is classified, and anything malformed or unfamiliar takes the full +application route. The same policy also produces the app-input fingerprint that a +later workflow can use to prove two commits have equivalent build inputs. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import os +import pathlib +import subprocess +import sys +from dataclasses import asdict, dataclass + + +SCHEMA = "flowlight-review-v1" + +SITE_ONLY_EXACT = frozenset( + { + "CNAME", + "CONTRIBUTING.md", + "LICENSE", + "README.md", + "SECURITY.md", + "product.md", + "scripts/build_site.py", + "scripts/check_site.py", + "site/site.css", + } +) + +SITE_ONLY_PREFIXES = ( + "docs/", + "site/i18n/", + "site/pages/", + "site/partials/", +) + +# Checked before the site allowlist. These files can sit inside a website-looking +# directory while still changing signed policy, release claims, or screenshot gates. +FULL_ROUTE_EXACT = frozenset( + { + "docs/assets/screenshots/manifest.json", + "site/pages/releases.html", + } +) + +FULL_ROUTE_PREFIXES = ( + ".github/", + "Flowlight/", + "Flowlight.xcodeproj/", + "FlowlightExtension/", + "FlowlightResponseScriptHelper/", + "FlowlightTests/", + "Shared/", + "ci_scripts/", + "docs/packs/", + "packaging/", + "rule-packs/", + "site/packs/", +) + +FULL_ROUTE_SCRIPT_EXACT = frozenset( + { + "project.yml", + "scripts/app-store-screenshots.sh", + "scripts/build-dmg.sh", + "scripts/build-pkg.sh", + "scripts/build-signed.sh", + "scripts/check_app_store_product.sh", + "scripts/check_release_checks.py", + "scripts/check_xcode_project.sh", + "scripts/classify_changes.py", + "scripts/notarize.sh", + "scripts/normalize_xcode_project.py", + "scripts/rule_pack_catalog.py", + "scripts/screenshot_manifest.py", + "scripts/screenshots.sh", + "scripts/test_classify_changes.py", + "scripts/test_release_checks.py", + "scripts/update-cask.sh", + } +) + + +@dataclass(frozen=True) +class Classification: + app: bool + site: bool + python: bool + actions: bool + pages: bool + site_only: bool + reason: str + paths: tuple[str, ...] + head_sha: str + tree: str + app_fingerprint: str + schema: str = SCHEMA + + +def git(repo: pathlib.Path, *arguments: str) -> bytes: + return subprocess.run( + ["git", "-C", os.fspath(repo), *arguments], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ).stdout + + +def safe_relative_path(raw: str) -> str | None: + if not raw or raw.startswith("/") or "\\" in raw: + return None + parts = pathlib.PurePosixPath(raw).parts + if not parts or any(part in {"", ".", ".."} for part in parts): + return None + return "/".join(parts) + + +def is_site_only_path(raw: str) -> bool: + path = safe_relative_path(raw) + if path is None: + return False + if path in FULL_ROUTE_EXACT or path in FULL_ROUTE_SCRIPT_EXACT: + return False + if path.startswith(FULL_ROUTE_PREFIXES): + return False + if path in SITE_ONLY_EXACT: + return True + return path.startswith(SITE_ONLY_PREFIXES) + + +def parse_name_status(payload: bytes) -> tuple[str, ...]: + fields = payload.split(b"\0") + if fields and fields[-1] == b"": + fields.pop() + paths: list[str] = [] + index = 0 + while index < len(fields): + status = os.fsdecode(fields[index]) + index += 1 + if not status or status[0] not in "ACDMRTUXB": + raise ValueError(f"unexpected Git diff status: {status!r}") + count = 2 if status[0] in "RC" else 1 + if index + count > len(fields): + raise ValueError(f"truncated Git diff record for {status!r}") + for _ in range(count): + path = os.fsdecode(fields[index]) + index += 1 + if safe_relative_path(path) is None: + raise ValueError(f"unsafe or malformed Git path: {path!r}") + paths.append(path) + return tuple(dict.fromkeys(paths)) + + +def changed_paths(repo: pathlib.Path, base: str, head: str) -> tuple[str, ...]: + git(repo, "cat-file", "-e", f"{base}^{{commit}}") + git(repo, "cat-file", "-e", f"{head}^{{commit}}") + return parse_name_status( + git(repo, "diff", "--name-status", "-z", "--find-renames", base, head, "--") + ) + + +def app_fingerprint(repo: pathlib.Path, head: str) -> str: + digest = hashlib.sha256() + digest.update(f"{SCHEMA}\0".encode()) + records = git(repo, "ls-tree", "-r", "-z", head).split(b"\0") + for record in records: + if not record: + continue + metadata, separator, raw_path = record.partition(b"\t") + if not separator: + raise ValueError("unexpected git ls-tree record") + path = os.fsdecode(raw_path) + if is_site_only_path(path): + continue + digest.update(raw_path) + digest.update(b"\0") + digest.update(metadata) + digest.update(b"\0") + return digest.hexdigest() + + +def classify(repo: pathlib.Path, base: str | None, head: str) -> Classification: + resolved_head = git(repo, "rev-parse", f"{head}^{{commit}}").decode().strip() + tree = git(repo, "rev-parse", f"{resolved_head}^{{tree}}").decode().strip() + fingerprint = app_fingerprint(repo, resolved_head) + + if not base or base == "0" * 40: + paths: tuple[str, ...] = () + app = True + reason = "No trustworthy base commit was supplied; using the full application route." + else: + try: + paths = changed_paths(repo, base, resolved_head) + except (OSError, subprocess.CalledProcessError, ValueError) as error: + paths = () + app = True + reason = f"Comparison failed closed to the full application route: {error}" + else: + app = not paths or any(not is_site_only_path(path) for path in paths) + reason = ( + "Every changed path is explicitly approved for website-only verification." + if not app + else "At least one changed path requires full application verification." + ) + + return Classification( + app=app, + site=True, + python=any(path.endswith(".py") for path in paths), + actions=any(path.startswith(".github/") for path in paths), + pages=any(path.startswith(("docs/", "site/")) for path in paths), + site_only=not app, + reason=reason, + paths=paths, + head_sha=resolved_head, + tree=tree, + app_fingerprint=fingerprint, + ) + + +def write_github_output(path: pathlib.Path, result: Classification) -> None: + values = asdict(result) + with path.open("a", encoding="utf-8") as output: + for key in ("app", "site", "python", "actions", "pages", "site_only"): + output.write(f"{key}={'true' if values[key] else 'false'}\n") + output.write(f"head_sha={result.head_sha}\n") + output.write(f"tree={result.tree}\n") + output.write(f"fingerprint={result.app_fingerprint}\n") + output.write(f"schema={result.schema}\n") + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--repo", type=pathlib.Path, default=pathlib.Path.cwd()) + parser.add_argument("--base") + parser.add_argument("--head", required=True) + parser.add_argument("--github-output", type=pathlib.Path) + args = parser.parse_args() + + try: + result = classify(args.repo.resolve(), args.base, args.head) + except (OSError, subprocess.CalledProcessError, ValueError) as error: + print(f"change classification failed: {error}", file=sys.stderr) + return 1 + + if args.github_output: + write_github_output(args.github_output, result) + json.dump(asdict(result), sys.stdout, indent=2, sort_keys=True) + sys.stdout.write("\n") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/screenshots.sh b/scripts/screenshots.sh index 49a70c7b..8f136c82 100755 --- a/scripts/screenshots.sh +++ b/scripts/screenshots.sh @@ -58,6 +58,9 @@ exact_app_pids() { command=$(ps -p "$pid" -o command=) [[ "$command" == "$expected" || "$command" == "$expected "* ]] && print -r -- "$pid" done + # A non-matching installed Flowlight may be the final loop item. Its comparison is not this helper's result: + # the output is the match set, and an empty set is a successful query rather than a capture failure under pipefail. + return 0 } stop_exact_app() { @@ -96,16 +99,7 @@ title_matches_screen() { } window_title() { - osascript - "$1" <<'OSA' -on run argv - tell application "System Events" - tell first application process whose unix id is (item 1 of argv as integer) - if (count of windows) is 0 then return "" - return name of first window - end tell - end tell -end run -OSA + scripts/window-id.swift --title "$1" } capture() { @@ -118,23 +112,30 @@ capture() { [ -z "$(exact_app_pids "$executable")" ] || { echo " exact candidate is already running"; return 1; } # The always-monitor shot asks for the representative "these agents are being monitored" banner, which real # inspection state (absent under the demo database) would otherwise never show. - local banner=() visualization=() + local banner=() visualization=() rules=() [ "$name" = "always-monitor" ] && banner=(-FLDemoBanner YES) [ "$name" = "visualize" ] && visualization=(-visualize.mode ai -visualize.presentation map -visualize.granularity hour) + [ "$name" = "rules" ] && rules=(-FLRulesTab packs) # Ignore macOS scene state: this launch is a deterministic fixture, and restored sidebar selection can otherwise # arrive after demo seeding and replace the requested screen. Pin English too, so the title check below is stable. - open -n "$APP" --args -ApplePersistenceIgnoreState YES -AppleLanguages "(en)" -AppleLocale en_US \ - -FLDemo YES -FLScreen "$screen" -FLAgentTab "${tab:-destinations}" \ + # Launch the exact executable directly. Launch Services may route arguments between simultaneous installations + # with the same bundle identifier, producing a real candidate window on the wrong screen. + "$executable" -ApplePersistenceIgnoreState YES -AppleLanguages "(en)" -AppleLocale en_US \ + -FLDemo YES -FLRenderLive YES -FLScreen "$screen" -FLAgentTab "${tab:-destinations}" \ -FLWindow "${w}x${h}" -FLInspectSelect paste.example -inspection.enabled NO \ -AppleInterfaceStyle Light \ - "${banner[@]}" "${visualization[@]}" - local pid="" + "${banner[@]}" "${visualization[@]}" "${rules[@]}" >/dev/null 2>&1 & + local pid=$! + local command="" for _ in {1..40}; do - pid=$(exact_app_pids "$executable" | head -1) - [ -n "$pid" ] && break + command=$(ps -p "$pid" -o command= 2>/dev/null || true) + [[ "$command" == "$executable" || "$command" == "$executable "* ]] && break sleep 0.25 done - [ -n "$pid" ] || { echo " couldn't find the candidate process"; return 1; } + [[ "$command" == "$executable" || "$command" == "$executable "* ]] || { + echo " couldn't verify the candidate process" + return 1 + } sleep "${FL_WAIT:-14}" # seeding 90 days of synthetic history, then the rollups it reads # A window that isn't key draws its close/minimise/zoom buttons grey, which is how every published # screenshot lost them. Bring the exact candidate forward and let the redraw land before the shutter. diff --git a/scripts/test_check_site.py b/scripts/test_check_site.py new file mode 100644 index 00000000..129f85ca --- /dev/null +++ b/scripts/test_check_site.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""Focused fixtures for navigation-derived site checks.""" + +from __future__ import annotations + +import importlib.util +import pathlib +import sys +import unittest + + +SCRIPT = pathlib.Path(__file__).with_name("check_site.py") +SPEC = importlib.util.spec_from_file_location("check_site", SCRIPT) +assert SPEC and SPEC.loader +check_site = importlib.util.module_from_spec(SPEC) +sys.modules[SPEC.name] = check_site +SPEC.loader.exec_module(check_site) + + +class SidebarOrderTests(unittest.TestCase): + def test_grouped_visible_order_is_authoritative(self): + source = """ + var items: [SidebarItem] { + let order: [SidebarItem] + switch self { + case .traffic: order = [.live, .agents, .reports, .visualize, .alerts] + case .investigate: order = [.ask, .inspect] + case .control: order = [.rules] + case .sources: order = [.devices, .coverage, .capture] + } + return order.filter { SidebarItem.availableCases.contains($0) } + } + """ + + self.assertEqual( + check_site.sidebar_order(source), + ["live", "agents", "reports", "visualize", "alerts", "ask", "inspect", + "rules", "devices", "coverage", "capture"], + ) + + def test_missing_grouped_order_fails_closed(self): + with self.assertRaises(ValueError): + check_site.sidebar_order("enum SidebarItem { case live, alerts }") + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/test_classify_changes.py b/scripts/test_classify_changes.py new file mode 100644 index 00000000..8ce5dfa6 --- /dev/null +++ b/scripts/test_classify_changes.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +"""Focused fixtures for the fail-closed review classifier.""" + +from __future__ import annotations + +import importlib.util +import pathlib +import subprocess +import sys +import tempfile +import unittest + + +SCRIPT = pathlib.Path(__file__).with_name("classify_changes.py") +SPEC = importlib.util.spec_from_file_location("classify_changes", SCRIPT) +assert SPEC and SPEC.loader +classifier = importlib.util.module_from_spec(SPEC) +sys.modules[SPEC.name] = classifier +SPEC.loader.exec_module(classifier) + + +class PathPolicyTests(unittest.TestCase): + def test_explicit_website_inputs_are_site_only(self): + paths = ( + "README.md", + "site/site.css", + "site/pages/docs.html", + "site/i18n/de.json", + "docs/index.html", + "docs/assets/screenshots/live.png", + "scripts/build_site.py", + ) + self.assertTrue(all(classifier.is_site_only_path(path) for path in paths)) + + def test_release_catalog_manifest_and_workflow_inputs_force_full(self): + paths = ( + ".github/workflows/ci.yml", + "Flowlight/UI/ContentView.swift", + "FlowlightTests/HelpTests.swift", + "Shared/RulePack.swift", + "project.yml", + "packaging/app-store/screenshots/macos/01-connections.png", + "rule-packs/official-source.json", + "site/packs/v1/official.json", + "docs/packs/v1/official.json", + "docs/assets/screenshots/manifest.json", + "site/pages/releases.html", + "scripts/screenshots.sh", + "scripts/classify_changes.py", + ) + self.assertTrue(all(not classifier.is_site_only_path(path) for path in paths)) + + def test_unknown_and_malformed_paths_force_full(self): + for path in ("new-area/file.txt", "../outside", "/absolute", "bad\\path"): + self.assertFalse(classifier.is_site_only_path(path), path) + + def test_rename_and_copy_records_classify_both_paths(self): + payload = b"R100\0docs/old.html\0Flowlight/New.swift\0C087\0README.md\0project.yml\0" + self.assertEqual( + classifier.parse_name_status(payload), + ("docs/old.html", "Flowlight/New.swift", "README.md", "project.yml"), + ) + + def test_truncated_rename_is_rejected(self): + with self.assertRaises(ValueError): + classifier.parse_name_status(b"R100\0docs/old.html\0") + + +class RepositoryTests(unittest.TestCase): + def setUp(self): + self.temp = tempfile.TemporaryDirectory() + self.repo = pathlib.Path(self.temp.name) + self.git("init", "-q") + self.git("config", "user.email", "classifier@example.invalid") + self.git("config", "user.name", "Classifier Test") + (self.repo / "Flowlight").mkdir() + (self.repo / "site").mkdir() + (self.repo / "Flowlight/App.swift").write_text("one\n") + (self.repo / "site/site.css").write_text("one\n") + self.commit("initial") + self.base = self.rev("HEAD") + + def tearDown(self): + self.temp.cleanup() + + def git(self, *args): + return subprocess.run( + ["git", "-C", self.repo, *args], check=True, text=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + ).stdout.strip() + + def rev(self, name): + return self.git("rev-parse", name) + + def commit(self, message): + self.git("add", ".") + self.git("commit", "-q", "-m", message) + + def test_site_change_keeps_fingerprint_and_skips_app(self): + before = classifier.app_fingerprint(self.repo, self.base) + (self.repo / "site/site.css").write_text("two\n") + self.commit("site") + result = classifier.classify(self.repo, self.base, "HEAD") + self.assertTrue(result.site_only) + self.assertFalse(result.app) + self.assertEqual(result.app_fingerprint, before) + + def test_app_change_updates_fingerprint_and_requires_app(self): + before = classifier.app_fingerprint(self.repo, self.base) + (self.repo / "Flowlight/App.swift").write_text("two\n") + self.commit("app") + result = classifier.classify(self.repo, self.base, "HEAD") + self.assertTrue(result.app) + self.assertFalse(result.site_only) + self.assertNotEqual(result.app_fingerprint, before) + + def test_missing_base_fails_closed_but_still_emits_identity(self): + result = classifier.classify(self.repo, None, "HEAD") + self.assertTrue(result.app) + self.assertEqual(result.head_sha, self.rev("HEAD")) + self.assertEqual(result.tree, self.rev("HEAD^{tree}")) + self.assertEqual(len(result.app_fingerprint), 64) + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/window-id.swift b/scripts/window-id.swift index 162292d7..c368aa65 100755 --- a/scripts/window-id.swift +++ b/scripts/window-id.swift @@ -1,7 +1,11 @@ #!/usr/bin/env swift -// Prints the window number of Flowlight's main window, optionally restricted to one exact process ID. +// Prints the window number—or, with --title, the title—of Flowlight's main window, optionally restricted to one +// exact process ID. Both screenshot identity checks come from Core Graphics, so Accessibility permission cannot make +// title lookup fail while capture still sees the window. import AppKit -let requestedPID = CommandLine.arguments.dropFirst().first.flatMap(Int.init) +let arguments = Array(CommandLine.arguments.dropFirst()) +let titleOnly = arguments.first == "--title" +let requestedPID = (titleOnly ? arguments.dropFirst().first : arguments.first).flatMap(Int.init) let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? [] let match = windows.first { info in let ownsWindow = requestedPID.map { (info[kCGWindowOwnerPID as String] as? Int) == $0 } @@ -9,4 +13,10 @@ let match = windows.first { info in return ownsWindow && ((info[kCGWindowBounds as String] as? [String: Any])?["Height"] as? Double ?? 0) > 400 } -if let number = match?[kCGWindowNumber as String] as? Int { print(number) } else { exit(1) } +if titleOnly { + if let title = match?[kCGWindowName as String] as? String, !title.isEmpty { print(title) } else { exit(1) } +} else if let number = match?[kCGWindowNumber as String] as? Int { + print(number) +} else { + exit(1) +} diff --git a/site/pages/de/docs.html b/site/pages/de/docs.html index 484c0f05..5f9da72f 100644 --- a/site/pages/de/docs.html +++ b/site/pages/de/docs.html @@ -97,16 +97,16 @@

Die AnsichtenLive⌘1Was sich gerade bewegt: Raten pro App über die letzten Sekunden und das meistgenutzte Ziel. KI-Agenten⌘2Welche Agenten aktiv sind, welche KI-Anbieter sie nutzen und mit wem sie sonst gesprochen haben. Verlauf⌘3Wohin der Datenverkehr ging, von der Sekunde bis zum Jahr. Gruppiert nach App, Ziel oder IP; umschaltbar auf Diagramme oder Genauer hinsehen; CSV-Export. - Verbindungen—Eine stabile Karte der Apps und ihrer genauen Ziele mit gewichteten Pfaden, bewegten Richtungsmarkern, Verbindungszahlen und einer gleichwertigen Liste. - Warnungen⌘4Alles, was ungewöhnlich aussah, mit App, Ziel und dem Wert, der die Regel ausgelöst hat. - Regeln⌘5Jede Erlaubnisliste und jede Verweigerung, die du gesetzt hast, was jede davon abdeckt und was sie tatsächlich gestoppt hat. + Verbindungen⌘4Eine stabile Karte der Apps und ihrer genauen Ziele mit gewichteten Pfaden, bewegten Richtungsmarkern, Verbindungszahlen und einer gleichwertigen Liste. + Warnungen⌘5Alles, was ungewöhnlich aussah, mit App, Ziel und dem Wert, der die Regel ausgelöst hat. + Regeln⌘8Jede Erlaubnisliste und jede Verweigerung, die du gesetzt hast, was jede davon abdeckt und was sie tatsächlich gestoppt hat. Fragen⌘6Fragen zu deinem eigenen Datenverkehr in normaler Sprache, beantwortet aus der aufgezeichneten Historie von einem lokalen oder einem gehosteten Modell. Inspizieren⌘7Optional: entschlüsselte Anfragen der Agenten, die du über Flowlight leitest, und die Tool-Aufrufe dahinter. Die Suche reicht in Anfrage- und Antwort-Bodys hinein. - Geräte⌘8Aus, bis du es einschaltest: Bluetooth, USB und externe Speicher, die ein Mac genauso nutzt wie das Netzwerk. - Abdeckung⌘9Was Flowlight nicht belegen kann – pro App, ob sein Datenverkehr gesehen, benannt und lesbar war. - Erfassung⌘0Welche Engine aufzeichnet, der Zustand der Erweiterung, das Lernen von Hostnamen und wo die Datenbank liegt. + Geräte⌘9Aus, bis du es einschaltest: Bluetooth, USB und externe Speicher, die ein Mac genauso nutzt wie das Netzwerk. + Abdeckung⌘0Was Flowlight nicht belegen kann – pro App, ob sein Datenverkehr gesehen, benannt und lesbar war. + Erfassung—Welche Engine aufzeichnet, der Zustand der Erweiterung, das Lernen von Hostnamen und wo die Datenbank liegt. -

Die Kurzbefehle sind die Reihenfolge der Seitenleiste, deshalb ist ⌘0 das zehnte Element und keine übersprungene Position.

+

Die Kurzbefehle folgen der Reihenfolge der Seitenleiste: ⌘0 ist das zehnte Element, und das elfte bleibt ohne einen erfundenen Kurzbefehl erreichbar.

Der Bildschirm Live: eine Liste von Anwendungen mit ihren aktuellen Sende- und Empfangsraten und ihrem meistgenutzten Ziel.
Live, der Bildschirm, mit dem Flowlight startet.
diff --git a/site/pages/de/index.html b/site/pages/de/index.html index 0ac4346d..8777fdf4 100644 --- a/site/pages/de/index.html +++ b/site/pages/de/index.html @@ -108,17 +108,17 @@

KI-Agenten

Was tun meine Agenten, außer ihr Modell zu rufen? Anbiete

Verlauf

Wo ist alles hingegangen? Sekunde bis Jahr, gruppiert nach App, Ziel oder IP, mit Diagrammen und CSV.

⌘3
-

Warnungen

Was sah falsch aus? Nachvollziehbare Warnungen pro App, mit Ziel und Schwellenwert.

⌘4
+

Warnungen

Was sah falsch aus? Nachvollziehbare Warnungen pro App, mit Ziel und Schwellenwert.

⌘5
-

Regeln

Was habe ich verweigert – und passiert es? Jede Regel, was sie blockiert hat, und ein Verlauf jeder Entscheidung.

⌘5
+

Regeln

Was habe ich verweigert – und passiert es? Jede Regel, was sie blockiert hat, und ein Verlauf jeder Entscheidung.

⌘8

Fragen

Fragen in normaler Sprache, beantwortet aus dem Verlauf – mit jeder ausgeführten Abfrage darunter.

⌘6
-

Geräte

Bluetooth, USB und Kameras: was gekoppelt, angeschlossen oder aktiv ist und wann sich das geändert hat. Aus, bis du es einschaltest.

⌘8
+

Geräte

Bluetooth, USB und Kameras: was gekoppelt, angeschlossen oder aktiv ist und wann sich das geändert hat. Aus, bis du es einschaltest.

⌘9

Inspizieren

Optional. Was hat der Agent wirklich gesendet, und welcher Tool-Aufruf hat es ausgelöst? Entschlüsselte Anfragen, Tool-Aufrufe, Ergebnisse.

⌘7
-

Verbindungen

Was kommuniziert? Eine zoombare Sankey-Karte für App-Verkehr und nachgewiesene KI-Agentenpfade, mit exakter Listenansicht.

+

Verbindungen

Was kommuniziert? Eine zoombare Sankey-Karte für App-Verkehr und nachgewiesene KI-Agentenpfade, mit exakter Listenansicht.

⌘4 diff --git a/site/pages/docs.html b/site/pages/docs.html index 9f958d4a..f78ffce9 100644 --- a/site/pages/docs.html +++ b/site/pages/docs.html @@ -98,16 +98,16 @@

The views

Live⌘1What's moving right now: per-app rates over the last few seconds and the busiest destination. AI Agents⌘2Which agents are active, which AI providers they use, and what else they contacted. History⌘3Where traffic went, from a 15-minute preset through all retained history. Group by App, Destination or IP; switch to Charts or Worth a look; export CSV. - Connections—A stable map of apps and their exact destinations, with weighted paths, moving direction markers, connection counts, and an equivalent list. - Alerts⌘4Everything that looked unusual, with the app, the destination and the number that tripped the rule. - Rules⌘5Every allowlist and refusal you have set, what each one covers, and what it has actually stopped. + Connections⌘4A stable map of apps and their exact destinations, with weighted paths, moving direction markers, connection counts, and an equivalent list. + Alerts⌘5Everything that looked unusual, with the app, the destination and the number that tripped the rule. Ask⌘6Questions about your own traffic in plain language, answered from the recorded history by a local or a hosted model. Inspect⌘7Optional: decrypted requests from the agents you route through Flowlight, and the tool calls behind them. Search reaches into request and response bodies. - Devices⌘8Off until you turn it on: camera activity, Bluetooth, USB and external storage. - Coverage⌘9What Flowlight cannot account for — per app, whether its traffic was seen, named, and readable. - Capture⌘0Which engine is recording, the extension's state, hostname learning, and where the database lives. + Rules⌘8Every allowlist and refusal you have set, what each one covers, and what it has actually stopped. + Devices⌘9Off until you turn it on: camera activity, Bluetooth, USB and external storage. + Coverage⌘0What Flowlight cannot account for — per app, whether its traffic was seen, named, and readable. + Capture—Which engine is recording, the extension's state, hostname learning, and where the database lives. -

The shortcuts are the sidebar's order, so ⌘0 is the tenth item rather than a skipped position.

+

The shortcuts follow the sidebar's visible order: ⌘0 is the tenth item, and an eleventh remains available without an invented key.

The Live screen: a list of applications with their current send and receive rates and busiest destination.
Live, the screen Flowlight opens on.
@@ -213,7 +213,7 @@

Other alerts

Apple's own apps are left out by default. macOS contacts Apple constantly — Software Update, iCloud, push, time, Maps tiles — on hosts and ports that are new the first time they appear, and listing all of it buries the one - line worth reading. Turn it off in Settings › Alerts if you want them. Either way the traffic is still + line worth reading. Turn it off in Settings › Detection › Rules if you want them. Either way the traffic is still recorded, still appears in Live, History and Ask, and is still subject to every rule, guardrail and allowlist: the setting decides what is listed, never what is allowed.

diff --git a/site/pages/es/docs.html b/site/pages/es/docs.html index c6802fa6..60079f0d 100644 --- a/site/pages/es/docs.html +++ b/site/pages/es/docs.html @@ -97,16 +97,16 @@

Las vistas

En vivo⌘1Qué se mueve ahora mismo: tasas por app en los últimos segundos y el destino más activo. Agentes de IA⌘2Qué agentes están activos, qué proveedores de IA usan y con qué más han contactado. Historial⌘3Adónde fue el tráfico, del segundo al año. Agrupa por App, Destino o IP; cambia a Gráficos o a Merece un vistazo; exporta a CSV. - Conexiones—Un mapa estable de apps y sus destinos exactos, con rutas ponderadas, marcadores de dirección en movimiento, recuentos de conexiones y una lista equivalente. - Alertas⌘4Todo lo que ha resultado inusual, con la app, el destino y la cifra que activó la regla. - Reglas⌘5Cada lista de permitidos y cada rechazo que hayas puesto, qué abarca cada uno y qué ha detenido realmente. + Conexiones⌘4Un mapa estable de apps y sus destinos exactos, con rutas ponderadas, marcadores de dirección en movimiento, recuentos de conexiones y una lista equivalente. + Alertas⌘5Todo lo que ha resultado inusual, con la app, el destino y la cifra que activó la regla. + Reglas⌘8Cada lista de permitidos y cada rechazo que hayas puesto, qué abarca cada uno y qué ha detenido realmente. Preguntar⌘6Preguntas sobre tu propio tráfico en lenguaje corriente, respondidas a partir del historial registrado por un modelo local o alojado. Inspeccionar⌘7Opcional: las peticiones descifradas de los agentes que encamines por Flowlight, y las llamadas de herramientas que hay detrás. La búsqueda llega a los cuerpos de las peticiones y las respuestas. - Dispositivos⌘8Desactivado hasta que lo enciendes: Bluetooth, USB y almacenamiento externo, que un Mac usa tanto como usa la red. - Cobertura⌘9Lo que Flowlight no puede contabilizar — por app, si su tráfico se vio, se nombró y se pudo leer. - Captura⌘0Qué motor está registrando, el estado de la extensión, el aprendizaje de nombres de host y dónde está la base de datos. + Dispositivos⌘9Desactivado hasta que lo enciendes: Bluetooth, USB y almacenamiento externo, que un Mac usa tanto como usa la red. + Cobertura⌘0Lo que Flowlight no puede contabilizar — por app, si su tráfico se vio, se nombró y se pudo leer. + Captura—Qué motor está registrando, el estado de la extensión, el aprendizaje de nombres de host y dónde está la base de datos. -

Los atajos son el orden de la barra lateral, así que ⌘0 es el décimo elemento y no una posición omitida.

+

Los atajos siguen el orden de la barra lateral: ⌘0 es el décimo elemento y el undécimo sigue disponible sin inventar una tecla.

La pantalla En vivo: una lista de aplicaciones con sus tasas actuales de envío y recepción y su destino más activo.
En vivo, la pantalla con la que se abre Flowlight.
diff --git a/site/pages/es/index.html b/site/pages/es/index.html index fe2acc4e..5e5a2d5f 100644 --- a/site/pages/es/index.html +++ b/site/pages/es/index.html @@ -108,17 +108,17 @@

Agentes de IA

¿Qué hacen mis agentes aparte de llamar a su modelo?

Historial

¿Adónde ha ido todo? Del segundo al año, agrupado por app, destino o IP, con gráficos y CSV.

⌘3
-

Alertas

¿Qué ha pintado mal? Alertas por app, explicables, con el destino y el umbral.

⌘4
+

Alertas

¿Qué ha pintado mal? Alertas por app, explicables, con el destino y el umbral.

⌘5
-

Reglas

¿Qué he rechazado y se está cumpliendo? Cada regla, lo que ha bloqueado y un flujo con todas las decisiones.

⌘5
+

Reglas

¿Qué he rechazado y se está cumpliendo? Cada regla, lo que ha bloqueado y un flujo con todas las decisiones.

⌘8

Preguntar

Preguntas en lenguaje corriente, respondidas con el historial, y debajo cada consulta que ejecutó.

⌘6
-

Dispositivos

Bluetooth, USB y cámaras: qué está emparejado, conectado o activo y cuándo cambió. Desactivado hasta que lo actives.

⌘8
+

Dispositivos

Bluetooth, USB y cámaras: qué está emparejado, conectado o activo y cuándo cambió. Desactivado hasta que lo actives.

⌘9

Inspeccionar

Opcional. ¿Qué envió el agente en realidad y qué llamada de herramienta lo provocó? Peticiones descifradas, llamadas de herramientas, resultados.

⌘7
-

Conexiones

¿Qué se comunica? Un mapa Sankey ampliable del tráfico de apps y las rutas comprobadas de agentes de IA, con una lista exacta equivalente.

+

Conexiones

¿Qué se comunica? Un mapa Sankey ampliable del tráfico de apps y las rutas comprobadas de agentes de IA, con una lista exacta equivalente.

⌘4 diff --git a/site/pages/fr/docs.html b/site/pages/fr/docs.html index 4c0f49a6..2c4a10f9 100644 --- a/site/pages/fr/docs.html +++ b/site/pages/fr/docs.html @@ -97,16 +97,16 @@

Les vues

En direct⌘1Ce qui circule en ce moment : les débits par app sur les dernières secondes et la destination la plus active. Agents IA⌘2Quels agents sont actifs, quels fournisseurs d’IA ils utilisent, et quoi d’autre ils ont contacté. Historique⌘3Où le trafic est parti, de la seconde à l’année. Groupez par App, Destination ou IP ; passez aux Graphiques ou à À regarder de près ; exportez en CSV. - Connexions—Une carte stable des apps et de leurs destinations exactes, avec des chemins pondérés, des marqueurs de direction animés, le nombre de connexions et une liste équivalente. - Alertes⌘4Tout ce qui a paru inhabituel, avec l’app, la destination et le chiffre qui a déclenché la règle. - Règles⌘5Chaque liste d’autorisation et chaque refus que vous avez posés, ce que chacun couvre, et ce qu’il a réellement arrêté. + Connexions⌘4Une carte stable des apps et de leurs destinations exactes, avec des chemins pondérés, des marqueurs de direction animés, le nombre de connexions et une liste équivalente. + Alertes⌘5Tout ce qui a paru inhabituel, avec l’app, la destination et le chiffre qui a déclenché la règle. + Règles⌘8Chaque liste d’autorisation et chaque refus que vous avez posés, ce que chacun couvre, et ce qu’il a réellement arrêté. Demander⌘6Des questions sur votre propre trafic en langage courant, auxquelles un modèle local ou hébergé répond à partir de l’historique enregistré. Inspecter⌘7Facultatif : les requêtes déchiffrées des agents que vous faites passer par Flowlight, et les appels d’outils qui les ont causées. La recherche va jusque dans les corps de requête et de réponse. - Appareils⌘8Désactivé jusqu’à ce que vous l’activiez : Bluetooth, USB et stockage externe, dont un Mac se sert autant que du réseau. - Couverture⌘9Ce dont Flowlight ne peut pas rendre compte — par app, si son trafic a été vu, nommé et lisible. - Capture⌘0Quel moteur enregistre, l’état de l’extension, l’apprentissage des noms d’hôte, et où vit la base de données. + Appareils⌘9Désactivé jusqu’à ce que vous l’activiez : Bluetooth, USB et stockage externe, dont un Mac se sert autant que du réseau. + Couverture⌘0Ce dont Flowlight ne peut pas rendre compte — par app, si son trafic a été vu, nommé et lisible. + Capture—Quel moteur enregistre, l’état de l’extension, l’apprentissage des noms d’hôte, et où vit la base de données. -

Les raccourcis sont l’ordre de la barre latérale, donc ⌘0 est le dixième élément plutôt qu’une position omise.

+

Les raccourcis suivent l’ordre de la barre latérale : ⌘0 est le dixième élément et le onzième reste accessible sans inventer de touche.

L’écran En direct : une liste d’applications avec leurs débits d’envoi et de réception actuels et leur destination la plus active.
En direct, l’écran sur lequel Flowlight s’ouvre.
diff --git a/site/pages/fr/index.html b/site/pages/fr/index.html index ec829500..15fcbc9a 100644 --- a/site/pages/fr/index.html +++ b/site/pages/fr/index.html @@ -108,17 +108,17 @@

Agents IA

Que font mes agents en plus d’appeler leur modèle ?

Historique

Où tout cela est-il parti ? De la seconde à l’année, par app, par destination ou par IP, avec graphiques et CSV.

⌘3
-

Alertes

Qu’est-ce qui clochait ? Des alertes explicables, par app, avec la destination et le seuil.

⌘4
+

Alertes

Qu’est-ce qui clochait ? Des alertes explicables, par app, avec la destination et le seuil.

⌘5
-

Règles

Qu’ai-je refusé, et est-ce bien appliqué ? Chaque règle, ce qu’elle a bloqué, et le flux de toutes les décisions.

⌘5
+

Règles

Qu’ai-je refusé, et est-ce bien appliqué ? Chaque règle, ce qu’elle a bloqué, et le flux de toutes les décisions.

⌘8

Demander

Des questions en langage courant, auxquelles l’historique répond — avec la liste des requêtes exécutées juste en dessous.

⌘6
-

Appareils

Bluetooth, USB et caméras : ce qui est appairé, branché ou actif, et quand cela a changé. Désactivé jusqu’à ce que vous l’activiez.

⌘8
+

Appareils

Bluetooth, USB et caméras : ce qui est appairé, branché ou actif, et quand cela a changé. Désactivé jusqu’à ce que vous l’activiez.

⌘9

Inspecter

Facultatif. Qu’a réellement envoyé l’agent, et quel appel d’outil en est la cause ? Requêtes déchiffrées, appels d’outils, résultats.

⌘7
-

Connexions

Qui communique ? Une carte Sankey zoomable du trafic des apps et des chemins attestés des agents IA, avec une liste exacte équivalente.

+

Connexions

Qui communique ? Une carte Sankey zoomable du trafic des apps et des chemins attestés des agents IA, avec une liste exacte équivalente.

⌘4 diff --git a/site/pages/index.html b/site/pages/index.html index 7dd84177..72baa548 100644 --- a/site/pages/index.html +++ b/site/pages/index.html @@ -117,17 +117,17 @@

AI Agents

What are my agents doing besides calling their model? Provi

History

Where did it all go? From 15 minutes through all history, grouped by app, destination or IP, with charts and CSV.

⌘3
-

Alerts

What looked wrong? Explainable, per-app alerts with the destination and the threshold.

⌘4
+

Alerts

What looked wrong? Explainable, per-app alerts with the destination and the threshold.

⌘5
-

Rules

What have I refused, and is it happening? Every rule, what each has blocked, and a feed of every decision.

⌘5
+

Rules

What have I refused, and is it happening? Every rule, what each has blocked, and a feed of every decision.

⌘8

Ask

Questions in plain language, answered from the history — with every query it ran listed underneath.

⌘6
-

Devices

Bluetooth, USB, and cameras: what's paired, what's attached or active, and when that changed. Off until you turn it on.

⌘8
+

Devices

Bluetooth, USB, and cameras: what's paired, what's attached or active, and when that changed. Off until you turn it on.

⌘9

Inspect

Optional. What did the agent actually send, and which tool call made it? Decrypted requests, tool calls, results.

⌘7
-

Connections

What is communicating? A zoomable Sankey map for app traffic and proved AI-agent paths, with exact list parity.

+

Connections

What is communicating? A zoomable Sankey map for app traffic and proved AI-agent paths, with exact list parity.

⌘4 diff --git a/site/pages/it/docs.html b/site/pages/it/docs.html index 2fbbd7ac..756b30c6 100644 --- a/site/pages/it/docs.html +++ b/site/pages/it/docs.html @@ -97,16 +97,16 @@

Le viste

In diretta⌘1Cosa si muove adesso: velocità per app negli ultimi secondi e la destinazione più trafficata. Agenti IA⌘2Quali agenti sono attivi, quali provider IA usano e cos'altro hanno contattato. Cronologia⌘3Dove è andato il traffico, dal secondo all'anno. Raggruppa per App, Destinazione o IP; passa a Grafici o a Vale un'occhiata; esporta in CSV. - Connessioni—Una mappa stabile delle app e delle destinazioni esatte, con percorsi ponderati, indicatori di direzione in movimento, conteggi delle connessioni e un elenco equivalente. - Avvisi⌘4Tutto ciò che è sembrato insolito, con l'app, la destinazione e il numero che ha fatto scattare la regola. - Regole⌘5Ogni elenco consentiti e ogni rifiuto che hai impostato, cosa copre ciascuno e cosa ha fermato davvero. + Connessioni⌘4Una mappa stabile delle app e delle destinazioni esatte, con percorsi ponderati, indicatori di direzione in movimento, conteggi delle connessioni e un elenco equivalente. + Avvisi⌘5Tutto ciò che è sembrato insolito, con l'app, la destinazione e il numero che ha fatto scattare la regola. + Regole⌘8Ogni elenco consentiti e ogni rifiuto che hai impostato, cosa copre ciascuno e cosa ha fermato davvero. Chiedi⌘6Domande sul tuo traffico in linguaggio naturale, a cui un modello locale o ospitato risponde a partire dalla cronologia registrata. Ispeziona⌘7Opzionale: le richieste decifrate degli agenti che instradi attraverso Flowlight e le chiamate agli strumenti che le hanno prodotte. La ricerca entra nei corpi di richieste e risposte. - Dispositivi⌘8Disattivato finché non lo attivi: Bluetooth, USB e archiviazione esterna, che un Mac usa tanto quanto usa la rete. - Copertura⌘9Ciò che Flowlight non può contabilizzare — per ogni app, se il suo traffico è stato visto, nominato e leggibile. - Acquisizione⌘0Quale motore sta registrando, lo stato dell'estensione, l'apprendimento dei nomi host e dove si trova il database. + Dispositivi⌘9Disattivato finché non lo attivi: Bluetooth, USB e archiviazione esterna, che un Mac usa tanto quanto usa la rete. + Copertura⌘0Ciò che Flowlight non può contabilizzare — per ogni app, se il suo traffico è stato visto, nominato e leggibile. + Acquisizione—Quale motore sta registrando, lo stato dell'estensione, l'apprendimento dei nomi host e dove si trova il database. -

Le scorciatoie sono l'ordine della barra laterale, quindi ⌘0 è il decimo elemento e non una posizione omessa.

+

Le scorciatoie seguono l'ordine della barra laterale: ⌘0 è il decimo elemento e l'undicesimo resta disponibile senza inventare un tasto.

La schermata In diretta: un elenco di applicazioni con le loro velocità attuali di invio e ricezione e la destinazione più trafficata.
In diretta, la schermata con cui Flowlight si apre.
diff --git a/site/pages/it/index.html b/site/pages/it/index.html index 6b2d448b..d664c687 100644 --- a/site/pages/it/index.html +++ b/site/pages/it/index.html @@ -108,17 +108,17 @@

Agenti IA

Cosa fanno i miei agenti oltre a chiamare il modello? Provi

Cronologia

Dove è finito tutto? Dal secondo all'anno, per app, destinazione o IP, con grafici e CSV.

⌘3
-

Avvisi

Cosa non tornava? Avvisi per app, spiegati, con la destinazione e la soglia.

⌘4
+

Avvisi

Cosa non tornava? Avvisi per app, spiegati, con la destinazione e la soglia.

⌘5
-

Regole

Cosa ho rifiutato, e sta funzionando? Ogni regola, che cosa ha bloccato e il flusso di tutte le decisioni.

⌘5
+

Regole

Cosa ho rifiutato, e sta funzionando? Ogni regola, che cosa ha bloccato e il flusso di tutte le decisioni.

⌘8

Chiedi

Domande in linguaggio naturale, con risposte tratte dalla cronologia e sotto l'elenco di tutte le query eseguite.

⌘6
-

Dispositivi

Bluetooth, USB e fotocamere: che cosa è abbinato, collegato o attivo e quando è cambiato. Disattivato finché non lo attivi.

⌘8
+

Dispositivi

Bluetooth, USB e fotocamere: che cosa è abbinato, collegato o attivo e quando è cambiato. Disattivato finché non lo attivi.

⌘9

Ispeziona

Opzionale. Cosa ha inviato davvero l'agente, e quale chiamata a uno strumento l'ha prodotta? Richieste decifrate, chiamate agli strumenti, risultati.

⌘7
-

Connessioni

Che cosa comunica? Una mappa Sankey ingrandibile del traffico delle app e dei percorsi comprovati degli agenti IA, con un elenco esatto equivalente.

+

Connessioni

Che cosa comunica? Una mappa Sankey ingrandibile del traffico delle app e dei percorsi comprovati degli agenti IA, con un elenco esatto equivalente.

⌘4 diff --git a/site/pages/ja/docs.html b/site/pages/ja/docs.html index 0afd1ad1..2b0a9321 100644 --- a/site/pages/ja/docs.html +++ b/site/pages/ja/docs.html @@ -95,16 +95,16 @@

各ビュー

ライブ⌘1いま何が動いているか。直近数秒間のアプリごとの速度と、最も忙しい接続先。 AI エージェント⌘2どのエージェントが動いていて、どの AI プロバイダを使い、ほかに何と通信したか。 履歴⌘3トラフィックがどこへ行ったか。秒から年まで。アプリ・接続先・IP でグループ化し、グラフや気になるものに切り替え、CSV に書き出せます。 - 接続—アプリと正確な接続先を、重み付き経路、動く方向マーカー、接続数、同等のリストで示す安定したマップ。 - アラート⌘4いつもと違って見えたものすべて。アプリ、接続先、そしてルールのしきい値を超えた数値とともに。 - ルール⌘5設定したすべての許可リストと拒否。それぞれが何を対象にし、実際に何を止めたか。 + 接続⌘4アプリと正確な接続先を、重み付き経路、動く方向マーカー、接続数、同等のリストで示す安定したマップ。 + アラート⌘5いつもと違って見えたものすべて。アプリ、接続先、そしてルールのしきい値を超えた数値とともに。 + ルール⌘8設定したすべての許可リストと拒否。それぞれが何を対象にし、実際に何を止めたか。 質問⌘6自分のトラフィックについての、ふつうの言葉での質問。記録された履歴から、ローカルまたはホスト型のモデルが答えます。 インスペクト⌘7任意。Flowlight を経由させたエージェントの復号済みリクエストと、その裏にあるツール呼び出し。検索はリクエストとレスポンスの本文にも届きます。 - デバイス⌘8オンにするまではオフ。Bluetooth、USB、外部ストレージ。Mac はネットワークと同じくらいこれらを使います。 - カバー範囲⌘9Flowlight が把握できないもの。アプリごとに、その通信が見えたか、名前が付いたか、読めたか。 - キャプチャ⌘0どのエンジンで記録しているか、機能拡張の状態、ホスト名の学習、そしてデータベースの場所。 + デバイス⌘9オンにするまではオフ。Bluetooth、USB、外部ストレージ。Mac はネットワークと同じくらいこれらを使います。 + カバー範囲⌘0Flowlight が把握できないもの。アプリごとに、その通信が見えたか、名前が付いたか、読めたか。 + キャプチャ—どのエンジンで記録しているか、機能拡張の状態、ホスト名の学習、そしてデータベースの場所。 -

ショートカットはサイドバーの並び順なので、⌘0 は飛ばされた番号ではなく 10 番目の項目です。

+

ショートカットはサイドバーの並び順です。⌘0 は 10 番目で、11 番目の項目には架空のキーを割り当てず、そのまま利用できます。

ライブビュー。アプリの一覧に、現在の送信と受信の速度、そして最も忙しい接続先が並んでいます。
ライブ。Flowlight が最初に開く画面です。
diff --git a/site/pages/ja/index.html b/site/pages/ja/index.html index 19d10e58..a4d1c25b 100644 --- a/site/pages/ja/index.html +++ b/site/pages/ja/index.html @@ -108,17 +108,17 @@

AI エージェント

エージェントはモデルを呼ぶ以外

履歴

結局どこへ行った?秒から年まで、アプリ・接続先・IP でグループ化、グラフと CSV 付き。

⌘3
-

アラート

何がおかしかった?理由がわかるアプリ単位のアラートに、接続先としきい値を添えて。

⌘4
+

アラート

何がおかしかった?理由がわかるアプリ単位のアラートに、接続先としきい値を添えて。

⌘5
-

ルール

何を拒否し、それは効いている?すべてのルール、それぞれがブロックしたもの、判定の履歴。

⌘5
+

ルール

何を拒否し、それは効いている?すべてのルール、それぞれがブロックしたもの、判定の履歴。

⌘8

質問

ふつうの言葉で聞けば、履歴から答えます。実行したクエリもすべて下に並びます。

⌘6
-

デバイス

Bluetooth、USB、カメラ。何がペアリング、接続、使用中で、いつ変わったか。自分でオンにするまではオフです。

⌘8
+

デバイス

Bluetooth、USB、カメラ。何がペアリング、接続、使用中で、いつ変わったか。自分でオンにするまではオフです。

⌘9

インスペクト

任意。エージェントは実際に何を送り、どのツール呼び出しが原因だった?復号したリクエスト、ツール呼び出し、結果。

⌘7
-

接続

何が通信している?アプリのトラフィックと確認済み AI エージェント経路を、ズームできる Sankey マップと同じ内容のリストで表示します。

+

接続

何が通信している?アプリのトラフィックと確認済み AI エージェント経路を、ズームできる Sankey マップと同じ内容のリストで表示します。

⌘4 diff --git a/site/pages/ko/docs.html b/site/pages/ko/docs.html index e8c57156..6986d6da 100644 --- a/site/pages/ko/docs.html +++ b/site/pages/ko/docs.html @@ -96,16 +96,16 @@

여러 뷰

실시간⌘1지금 무엇이 움직이나. 지난 몇 초 동안의 앱별 속도와 가장 바쁜 목적지. AI 에이전트⌘2어떤 에이전트가 활동 중이고, 어떤 AI 제공업체를 쓰며, 그 밖에 어디에 접속했나. 기록⌘3트래픽이 어디로 갔나. 초에서 연까지. 앱, 목적지, IP로 묶고, 차트나 눈여겨볼 것으로 바꾸고, CSV로 내보냅니다. - 연결—앱과 정확한 목적지를 가중 경로, 움직이는 방향 표시, 연결 수, 동등한 목록으로 보여 주는 안정적인 지도입니다. - 알림⌘4이상해 보인 모든 것. 앱과 목적지, 그리고 규칙의 기준을 넘긴 수치와 함께. - 규칙⌘5설정해 둔 모든 허용 목록과 거부, 각각이 무엇을 포괄하는지, 그리고 실제로 무엇을 막았는지. + 연결⌘4앱과 정확한 목적지를 가중 경로, 움직이는 방향 표시, 연결 수, 동등한 목록으로 보여 주는 안정적인 지도입니다. + 알림⌘5이상해 보인 모든 것. 앱과 목적지, 그리고 규칙의 기준을 넘긴 수치와 함께. + 규칙⌘8설정해 둔 모든 허용 목록과 거부, 각각이 무엇을 포괄하는지, 그리고 실제로 무엇을 막았는지. 질문⌘6내 트래픽에 대한 평범한 말로 된 질문. 기록된 이력에서 로컬 모델이나 호스팅 모델이 답합니다. 검사⌘7선택 사항. Flowlight를 거치도록 지정한 에이전트의 복호화된 요청과 그 뒤에 있는 도구 호출. 검색은 요청·응답 본문까지 들어갑니다. - 기기⌘8켤 때까지는 꺼져 있습니다. Bluetooth와 USB, 외장 저장 장치. Mac은 네트워크만큼이나 이것들을 씁니다. - 포착 범위⌘9Flowlight가 파악하지 못하는 것. 앱별로 그 트래픽이 보였는지, 이름이 붙었는지, 읽혔는지. - 캡처⌘0어떤 엔진이 기록 중인지, 확장의 상태, 호스트 이름 학습, 그리고 데이터베이스의 위치. + 기기⌘9켤 때까지는 꺼져 있습니다. Bluetooth와 USB, 외장 저장 장치. Mac은 네트워크만큼이나 이것들을 씁니다. + 포착 범위⌘0Flowlight가 파악하지 못하는 것. 앱별로 그 트래픽이 보였는지, 이름이 붙었는지, 읽혔는지. + 캡처—어떤 엔진이 기록 중인지, 확장의 상태, 호스트 이름 학습, 그리고 데이터베이스의 위치. -

단축키는 사이드바의 순서라서, ⌘0은 건너뛴 자리가 아니라 열 번째 항목입니다.

+

단축키는 사이드바 순서를 따릅니다. ⌘0은 열 번째 항목이고, 열한 번째 항목은 억지로 키를 만들지 않아도 계속 사용할 수 있습니다.

실시간 뷰: 앱 목록에 각각의 현재 보내기·받기 속도와 가장 바쁜 목적지가 함께 나열되어 있습니다.
실시간, Flowlight가 처음 여는 화면.
diff --git a/site/pages/ko/index.html b/site/pages/ko/index.html index fc83fa98..464e9842 100644 --- a/site/pages/ko/index.html +++ b/site/pages/ko/index.html @@ -108,17 +108,17 @@

AI 에이전트

에이전트가 모델을 부르는 것 말고 무엇

기록

다 어디로 갔나? 초에서 연까지, 앱·목적지·IP로 묶어 차트와 CSV로.

⌘3
-

알림

무엇이 이상했나? 목적지와 임계값까지 밝히는, 설명되는 앱별 알림.

⌘4
+

알림

무엇이 이상했나? 목적지와 임계값까지 밝히는, 설명되는 앱별 알림.

⌘5
-

규칙

무엇을 거부했고, 실제로 막히고 있나? 모든 규칙과 각 규칙이 막은 것, 그리고 모든 판정의 기록.

⌘5
+

규칙

무엇을 거부했고, 실제로 막히고 있나? 모든 규칙과 각 규칙이 막은 것, 그리고 모든 판정의 기록.

⌘8

질문

평소 쓰는 말로 묻고 기록에서 답을 받습니다. 실행된 질의는 아래에 전부 표시됩니다.

⌘6
-

기기

Bluetooth, USB, 카메라: 무엇이 페어링, 연결 또는 사용 중이며 언제 바뀌었나. 직접 켜기 전까지는 끔.

⌘8
+

기기

Bluetooth, USB, 카메라: 무엇이 페어링, 연결 또는 사용 중이며 언제 바뀌었나. 직접 켜기 전까지는 끔.

⌘9

검사

선택 사항. 에이전트가 실제로 무엇을 보냈고, 어떤 도구 호출이 그렇게 했나? 복호화된 요청, 도구 호출, 결과.

⌘7
-

연결

무엇이 통신하나? 앱 트래픽과 입증된 AI 에이전트 경로를 확대 가능한 Sankey 지도와 동일한 내용의 목록으로 보여 줍니다.

+

연결

무엇이 통신하나? 앱 트래픽과 입증된 AI 에이전트 경로를 확대 가능한 Sankey 지도와 동일한 내용의 목록으로 보여 줍니다.

⌘4 diff --git a/site/pages/pt-PT/docs.html b/site/pages/pt-PT/docs.html index 5e6a3756..2f89fc44 100644 --- a/site/pages/pt-PT/docs.html +++ b/site/pages/pt-PT/docs.html @@ -97,16 +97,16 @@

As vistas

Em direto⌘1O que se move neste momento: taxas por app nos últimos segundos e o destino mais ativo. Agentes de IA⌘2Que agentes estão ativos, que fornecedores de IA usam e com que mais contactaram. Histórico⌘3Para onde foi o tráfego, do segundo ao ano. Agrupe por App, Destino ou IP; mude para Gráficos ou Vale a pena ver; exporte em CSV. - Ligações—Um mapa estável das aplicações e dos destinos exatos, com caminhos ponderados, marcadores de direção em movimento, contagens de ligações e uma lista equivalente. - Alertas⌘4Tudo o que pareceu invulgar, com a app, o destino e o número que disparou a regra. - Regras⌘5Todas as listas de permissões e recusas que definiu, o que cada uma abrange e o que de facto travou. + Ligações⌘4Um mapa estável das aplicações e dos destinos exatos, com caminhos ponderados, marcadores de direção em movimento, contagens de ligações e uma lista equivalente. + Alertas⌘5Tudo o que pareceu invulgar, com a app, o destino e o número que disparou a regra. + Regras⌘8Todas as listas de permissões e recusas que definiu, o que cada uma abrange e o que de facto travou. Perguntar⌘6Perguntas sobre o seu próprio tráfego em linguagem simples, respondidas a partir do histórico registado por um modelo local ou alojado. Inspecionar⌘7Opcional: pedidos desencriptados dos agentes que encaminha pelo Flowlight e as chamadas de ferramentas por trás deles. A pesquisa entra nos corpos dos pedidos e das respostas. - Dispositivos⌘8Desligado até o ligar: Bluetooth, USB e armazenamento externo, que um Mac usa tanto como usa a rede. - Cobertura⌘9O que o Flowlight não consegue contabilizar — por app, se o seu tráfego foi visto, nomeado e legível. - Captura⌘0Que motor está a registar, o estado da extensão, a aprendizagem de nomes de anfitrião e onde está a base de dados. + Dispositivos⌘9Desligado até o ligar: Bluetooth, USB e armazenamento externo, que um Mac usa tanto como usa a rede. + Cobertura⌘0O que o Flowlight não consegue contabilizar — por app, se o seu tráfego foi visto, nomeado e legível. + Captura—Que motor está a registar, o estado da extensão, a aprendizagem de nomes de anfitrião e onde está a base de dados. -

Os atalhos seguem a ordem da barra lateral, por isso ⌘0 é o décimo item e não uma posição saltada.

+

Os atalhos seguem a ordem da barra lateral: ⌘0 é o décimo item e o décimo primeiro continua disponível sem inventar uma tecla.

A vista Em direto: uma lista de aplicações com as suas taxas de envio e receção atuais e o destino mais ativo.
Em direto, a vista com que o Flowlight abre.
diff --git a/site/pages/pt-PT/index.html b/site/pages/pt-PT/index.html index 986dd480..bb33f2c6 100644 --- a/site/pages/pt-PT/index.html +++ b/site/pages/pt-PT/index.html @@ -108,17 +108,17 @@

Agentes de IA

O que fazem os meus agentes além de chamar o modelo? F

Histórico

Para onde foi tudo? Do segundo ao ano, agrupado por app, destino ou IP, com gráficos e CSV.

⌘3
-

Alertas

O que pareceu errado? Alertas por app, explicáveis, com o destino e o limiar.

⌘4
+

Alertas

O que pareceu errado? Alertas por app, explicáveis, com o destino e o limiar.

⌘5
-

Regras

O que recusei e está a acontecer? Todas as regras, o que cada uma bloqueou e um fluxo de todas as decisões.

⌘5
+

Regras

O que recusei e está a acontecer? Todas as regras, o que cada uma bloqueou e um fluxo de todas as decisões.

⌘8

Perguntar

Perguntas em linguagem comum, respondidas a partir do histórico — com todas as consultas que fez listadas abaixo.

⌘6
-

Dispositivos

Bluetooth, USB e câmaras: o que está emparelhado, ligado ou ativo e quando isso mudou. Desativado até o ativar.

⌘8
+

Dispositivos

Bluetooth, USB e câmaras: o que está emparelhado, ligado ou ativo e quando isso mudou. Desativado até o ativar.

⌘9

Inspecionar

Opcional. O que é que o agente enviou de facto, e que chamada de ferramenta o fez? Pedidos desencriptados, chamadas de ferramentas, resultados.

⌘7
-

Ligações

O que está a comunicar? Um mapa Sankey ampliável do tráfego das apps e dos percursos comprovados dos agentes de IA, com uma lista exata equivalente.

+

Ligações

O que está a comunicar? Um mapa Sankey ampliável do tráfego das apps e dos percursos comprovados dos agentes de IA, com uma lista exata equivalente.

⌘4 diff --git a/site/pages/releases.html b/site/pages/releases.html index 8708db7f..ca8fb231 100644 --- a/site/pages/releases.html +++ b/site/pages/releases.html @@ -13,7 +13,18 @@

What's new

-

0.17.1

Latest
+

0.17.2

Latest
+
    +
  • Keep filtered evidence unmistakable. An active Focus now stays visible above every destination with its exact scope and one-click editing, while sidebar shortcuts follow the order shown on screen.
  • +
  • Make warning notifications respond immediately. Turning warnings on now requests macOS authorization in the same action, reports whether access is active, not requested, or denied, and opens System Settings when recovery is needed.
  • +
  • Stay ready for the next macOS. Live chart, table, rate, and source state now publish as one coherent snapshot, while sidebar selection waits for AppKit's callback to finish, removing a reentrant delegate operation that macOS warns will become an assertion.
  • +
  • Test the exact commit a review names. Pull-request CI and CodeQL explicitly check out the head SHA, a deny-first rename-aware classifier fails unknown and release inputs closed to the full app route, and one stable gate records the tested tree and app-input fingerprint.
  • +
  • Keep website work independent from app releases. Explicitly allowlisted website-only changes require no application version bump, while project, packaging, screenshot, signed-catalog, workflow, and other release inputs can never skip macOS verification.
  • +
+
+ +
+

0.17.1

  • Keep every public screenshot current. All ten website images now come from the same 0.17.1 demo build, consistently show History and Connections in the sidebar, and use History throughout linked actions and guidance.
  • Review the Store with the same product users receive. A complete 2880×1800 Mac App Store screenshot set is captured from that exact build, title-checked screen by screen, and retained with the release for App Store Connect.
  • diff --git a/site/pages/zh-Hans/docs.html b/site/pages/zh-Hans/docs.html index a0966c15..973768d8 100644 --- a/site/pages/zh-Hans/docs.html +++ b/site/pages/zh-Hans/docs.html @@ -93,16 +93,16 @@

    各个视图

    实时⌘1现在什么在动:最近几秒按应用的速率,以及最忙的目标。 AI 代理⌘2哪些代理在活动、它们用哪些 AI 提供方,以及它们还联系了什么。 历史⌘3流量去了哪里,从秒到年。按应用、目标或 IP 分组;切到图表或值得一看;导出 CSV。 - 连接—应用与其精确目标的稳定地图,带有按流量加权的路径、移动的方向标记、连接数以及等价列表。 - 警报⌘4所有看起来不寻常的事,带上应用、目标和触发规则的那个数字。 - 规则⌘5你设过的每一条允许列表和拒绝,各自管到哪里,以及实际拦下了什么。 + 连接⌘4应用与其精确目标的稳定地图,带有按流量加权的路径、移动的方向标记、连接数以及等价列表。 + 警报⌘5所有看起来不寻常的事,带上应用、目标和触发规则的那个数字。 + 规则⌘8你设过的每一条允许列表和拒绝,各自管到哪里,以及实际拦下了什么。 提问⌘6用平常的话问你自己的流量,由本地模型或托管模型从记录下来的历史里作答。 检查⌘7可选:你交给 Flowlight 转发的那些代理的解密请求,以及它们背后的工具调用。搜索能深入请求和响应正文。 - 设备⌘8你打开之前一直是关的:蓝牙、USB 与外置存储,一台 Mac 用它们跟用网络一样多。 - 覆盖范围⌘9Flowlight 说不清的部分——按应用,它的流量有没有被看到、被命名、被读懂。 - 捕获⌘0哪个引擎在记录、扩展的状态、主机名学习,以及数据库放在哪里。 + 设备⌘9你打开之前一直是关的:蓝牙、USB 与外置存储,一台 Mac 用它们跟用网络一样多。 + 覆盖范围⌘0Flowlight 说不清的部分——按应用,它的流量有没有被看到、被命名、被读懂。 + 捕获—哪个引擎在记录、扩展的状态、主机名学习,以及数据库放在哪里。 -

    快捷键就是侧边栏的顺序,所以 ⌘0 是第十项,不是被跳过的位置。

    +

    快捷键遵循侧边栏顺序:⌘0 是第十项,第十一项仍然可用,不会虚构一个按键。

    实时视图:一列应用,各自带着当前的发送与接收速率,以及最忙的目标。
    实时,Flowlight 打开时进入的那个视图。
    diff --git a/site/pages/zh-Hans/index.html b/site/pages/zh-Hans/index.html index 2e1aa978..858b7486 100644 --- a/site/pages/zh-Hans/index.html +++ b/site/pages/zh-Hans/index.html @@ -108,17 +108,17 @@

    AI 代理

    我的代理除了调用模型还在做什么?提供方

    历史

    流量究竟去了哪?从秒到年,按应用、目标或 IP 分组,配图表与 CSV。

    ⌘3
    -

    警报

    哪里不对?逐应用、讲得清道理的警报,带上目标和阈值。

    ⌘4
    +

    警报

    哪里不对?逐应用、讲得清道理的警报,带上目标和阈值。

    ⌘5
-

规则

我拒绝过什么,真的生效了吗?每条规则、各自阻止了什么,以及每次判定的流水。

⌘5
+

规则

我拒绝过什么,真的生效了吗?每条规则、各自阻止了什么,以及每次判定的流水。

⌘8

提问

用日常语言提问,从历史数据里作答——下方列出它执行过的每一条查询。

⌘6
-

设备

蓝牙、USB 和摄像头:配对了什么、接入或启用了什么、什么时候变的。默认关闭,你开了才记录。

⌘8
+

设备

蓝牙、USB 和摄像头:配对了什么、接入或启用了什么、什么时候变的。默认关闭,你开了才记录。

⌘9

检查

可选。代理究竟发出了什么,是哪次工具调用引起的?解密后的请求、工具调用和结果。

⌘7
-

连接

谁在通信?用可缩放的 Sankey 图展示应用流量和已证实的 AI 代理路径,并提供内容完全一致的列表。

+

连接

谁在通信?用可缩放的 Sankey 图展示应用流量和已证实的 AI 代理路径,并提供内容完全一致的列表。

⌘4 diff --git a/site/pages/zh-Hant/docs.html b/site/pages/zh-Hant/docs.html index e2d2c8eb..177501b7 100644 --- a/site/pages/zh-Hant/docs.html +++ b/site/pages/zh-Hant/docs.html @@ -96,16 +96,16 @@

各個畫面

即時⌘1現在有什麼在傳:最近幾秒各 App 的速率,以及最忙的目標。 AI 代理⌘2哪些代理在活動、它們用哪些 AI 供應商,以及它們還連過什麼。 歷史⌘3流量去了哪裡,從秒到年。依 App、目標或 IP 分組;切換到「圖表」或「值得一看」;匯出 CSV。 - 連線—應用程式與精確目的地的穩定地圖,包含加權路徑、移動方向標記、連線數與等價列表。 - 警示⌘4所有看起來不尋常的事,附上 App、目標,以及觸發規則的那個數字。 - 規則⌘5你設過的每一條允許清單和拒絕,各自管到哪裡,以及實際攔下了什麼。 + 連線⌘4應用程式與精確目的地的穩定地圖,包含加權路徑、移動方向標記、連線數與等價列表。 + 警示⌘5所有看起來不尋常的事,附上 App、目標,以及觸發規則的那個數字。 + 規則⌘8你設過的每一條允許清單和拒絕,各自管到哪裡,以及實際攔下了什麼。 提問⌘6用平常的話問你自己的流量,由本機模型或託管模型從記錄下來的歷史裡作答。 檢查⌘7選用:你轉送經過 Flowlight 的代理,其解密後的請求,以及背後的工具呼叫。搜尋也會查進請求與回應的內文。 - 裝置⌘8在你開啟之前都是關的:藍牙、USB 與外接儲存裝置,一台 Mac 用它們跟用網路一樣多。 - 涵蓋範圍⌘9Flowlight 說不清的部分 — 依 App 逐一列出,它的流量有沒有被看到、被命名、被讀懂。 - 擷取⌘0目前由哪個引擎記錄、延伸功能的狀態、主機名稱學習,以及資料庫存放的位置。 + 裝置⌘9在你開啟之前都是關的:藍牙、USB 與外接儲存裝置,一台 Mac 用它們跟用網路一樣多。 + 涵蓋範圍⌘0Flowlight 說不清的部分 — 依 App 逐一列出,它的流量有沒有被看到、被命名、被讀懂。 + 擷取—目前由哪個引擎記錄、延伸功能的狀態、主機名稱學習,以及資料庫存放的位置。 -

快速鍵就是側邊欄的順序,所以 ⌘0 是第十項,而不是被跳過的位置。

+

快速鍵遵循側邊欄順序:⌘0 是第十項,第十一項仍然可用,不會虛構一個按鍵。

即時畫面:一列 App,各自帶著目前的傳送與接收速率,以及最忙的目標。
即時,Flowlight 開啟時的那個畫面。
diff --git a/site/pages/zh-Hant/index.html b/site/pages/zh-Hant/index.html index 2212e616..5f5996a1 100644 --- a/site/pages/zh-Hant/index.html +++ b/site/pages/zh-Hant/index.html @@ -108,17 +108,17 @@

AI 代理

我的代理除了呼叫模型,還在做什麼?供應

歷史

流量都到哪去了?從秒到年,依 App、目標或 IP 分組,附圖表與 CSV。

⌘3
-

警示

哪裡看起來不對?每個 App 都有說得清楚的警示,附上目標和閾值。

⌘4
+

警示

哪裡看起來不對?每個 App 都有說得清楚的警示,附上目標和閾值。

⌘5
-

規則

我拒絕了什麼,真的有在擋嗎?每一條規則、各自封鎖過什麼,以及每一次決定的紀錄。

⌘5
+

規則

我拒絕了什麼,真的有在擋嗎?每一條規則、各自封鎖過什麼,以及每一次決定的紀錄。

⌘8

提問

用日常語言提問,從歷史記錄裡得到答案 — 下方還列出它跑過的每一條查詢。

⌘6
-

裝置

藍牙、USB 和攝影機:配對了什麼、接上或啟用了什麼,以及什麼時候變動的。要等你開啟才會作用。

⌘8
+

裝置

藍牙、USB 和攝影機:配對了什麼、接上或啟用了什麼,以及什麼時候變動的。要等你開啟才會作用。

⌘9

檢查

選用功能。代理實際送出了什麼,又是哪一次工具呼叫造成的?解密後的請求、工具呼叫、結果。

⌘7
-

連線

誰在通訊?用可縮放的 Sankey 圖顯示 App 流量和已證實的 AI 代理路徑,並提供內容完全一致的列表。

+

連線

誰在通訊?用可縮放的 Sankey 圖顯示 App 流量和已證實的 AI 代理路徑,並提供內容完全一致的列表。

⌘4