// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package preferences import ( "fmt" "slices" "strings" "git.stormux.org/storm/cthulhu/internal/tentacle" ) func tentacleUpdateCapabilities(entry tentacle.Entry, manifest tentacle.Manifest) string { var previous []string if entry.Presentation { previous = append(previous, "presentation") } if entry.Interaction { previous = append(previous, "interaction") } if entry.ReaderSettings { previous = append(previous, "reader-settings") } previous = append(previous, entry.RemoteGrants...) if len(previous) == 0 { previous = append(previous, "none") } declared := manifest.Capabilities if len(declared) == 0 { declared = []string{"none"} } return "Current capabilities: " + strings.Join(previous, ", ") + ". Repository declares: " + strings.Join(declared, ", ") + "." } func tentacleInstallConfirmation(entry tentacle.Entry, manifest tentacle.Manifest, label string) string { permissions := "This tentacle can register reader commands." if slices.Contains(manifest.Capabilities, "presentation") { permissions = "This tentacle can register reader commands and send speech and braille messages." } if slices.Contains(manifest.Capabilities, "interaction") { permissions = "This tentacle can register reader commands, send speech and braille messages, open internal forms, read the focused item and clipboard when invoked, and write clipboard text." } if slices.Contains(manifest.Capabilities, "reader-settings") { permissions += " It can also add preferences pages and quick settings, inspect speech voices, and temporarily change the reader voice configuration." } permissions += remotePermissions(manifest.Capabilities) return fmt.Sprintf("%s %s version %s from %s?\n\n%s\n\nOnly install packages from publishers you trust. Tentacles run with your account's access; resource limits do not protect your files or network.\n\nTentacle management changes take effect immediately.", label, entry.Name, entry.Version, entry.Repository, permissions) } func tentacleUpdateConfirmation(entry tentacle.Entry, update tentacle.AvailableUpdate, manifest tentacle.Manifest) string { permissions := tentacleUpdateCapabilities(entry, manifest) + remotePermissions(manifest.Capabilities) return fmt.Sprintf("Update %s from version %s to version %s?\n\n%s\n\nOnly update packages from publishers you trust. Tentacles run with your account's access.\n\nChanges take effect immediately.", update.Name, update.InstalledVersion, update.AvailableVersion, permissions) } // Install grants describe direction explicitly and never imply active consent. func remotePermissions(grants []string) string { descriptions := []struct{ grant, text string }{ {"output-observe", "share local reader output with the remote controller"}, {"remote-present", "present output received from the controlled computer"}, {"keyboard-capture", "capture local keyboard input for the controlled computer"}, {"keyboard-inject", "accept keyboard input from the remote controller"}, {"braille-stream", "exchange remote braille cells and supported display gestures"}, {"clipboard-exchange", "send clipboard text explicitly and receive text with session permission"}, } var requested []string for _, item := range descriptions { if slices.Contains(grants, item.grant) { requested = append(requested, item.text) } } if len(requested) == 0 { return "" } return " Requested remote access: " + strings.Join(requested, "; ") + ". Installation does not start a connection or authorize control. Each session requires local approval, and unavailable reader operations remain disabled." }