usage

package
v0.0.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2026 License: AGPL-3.0 Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	TerminationModeNone   TerminationMode = "none"
	TerminationModeBlock  TerminationMode = "block"
	TerminationModePaused TerminationMode = "paused"
	TerminationModeAllow  TerminationMode = "allow"

	TerminationModeSourceApplication TerminationModeSource = "application"
	TerminationModeSourceCustomRules TerminationModeSource = "custom_rules"
	TerminationModeSourceWhitelist   TerminationModeSource = "whitelist"
	TerminationModeSourcePaused      TerminationModeSource = "paused"

	ClassificationSourceUserSet     ClassificationSource = "user_set"
	ClassificationSourceObviously   ClassificationSource = "obviously"
	ClassificationSourceCloudLLM    ClassificationSource = "llm"
	ClassificationSourceCustomRules ClassificationSource = "custom_rules"

	ClassificationError       Classification = "unknown"
	ClassificationProductive  Classification = "productive"
	ClassificationDistracting Classification = "distracting"
	ClassificationNeutral     Classification = "neutral"
	ClassificationSystem      Classification = "system"
)

Variables

This section is empty.

Functions

func FetchMainContent

func FetchMainContent(ctx context.Context, rawURL string) (string, error)

Types

type Application

type Application struct {
	ID             int64  `gorm:"primaryKey;autoIncrement" json:"id"`
	Name           string `json:"name"`
	ExecutablePath string `json:"executable_path"`
	Icon           string `json:"icon"` // either app icon or favicon

	Hostname *string `json:"hostname" gorm:"uniqueIndex:idx_bundle_id"`
	Domain   *string `json:"domain"`

	// darwin only
	BundleID *string `json:"bundle_id" gorm:"uniqueIndex:idx_bundle_id;nullable"`
}

type ApplicationUsage

type ApplicationUsage struct {
	ID          int64   `gorm:"primaryKey;autoIncrement" json:"id"`
	WindowTitle string  `json:"window_title"`
	BrowserURL  *string `json:"browser_url" gorm:"type:text;nullable"`

	StartedAt       int64  `json:"started_at"`
	EndedAt         *int64 `json:"ended_at" gorm:"nullable"`
	DurationSeconds *int   `json:"duration_seconds" gorm:"nullable"`

	Classification           Classification       `gorm:"index:idx_classification" json:"classification"`
	ClassificationReasoning  string               `json:"classification_reasoning"`
	ClassificationError      *string              `gorm:"index:idx_classification_error" json:"classification_error"`
	ClassificationConfidence float32              `json:"classification_confidence"`
	ClassificationSource     ClassificationSource `json:"classification_source"`

	DetectedProject              string `gorm:"index:idx_detected_project" json:"detected_project"`
	DetectedCommunicationChannel string `gorm:"index:idx_detected_communication_channel" json:"detected_communication_channel"`

	TerminationMode      TerminationMode       `json:"termination_mode"`
	TerminationReasoning string                `json:"termination_reasoning"`
	TerminationSource    TerminationModeSource `json:"termination_mode_source"`
	TerminationError     string                `gorm:"index:idx_termination_mode_error" json:"termination_mode_error"`

	// relations
	Tags          []ApplicationUsageTags `gorm:"foreignKey:UsageID" json:"tags"`
	ApplicationID int64                  `json:"application_id"`
	Application   Application            `gorm:"foreignKey:ApplicationID" json:"application"`

	SandboxContext  string  `json:"sandbox_context" gorm:"type:text;nullable"`
	SandboxResponse *string `json:"sandbox_response" gorm:"type:text;nullable"`
	SandboxLogs     string  `json:"sandbox_logs" gorm:"type:text;nullable"`
}

func (*ApplicationUsage) Same

func (a *ApplicationUsage) Same(windowTitle, appName string, bundleID, url *string) bool

Same returns true if the application usage is the same as the given application usage

Application usage is considered the same if:

  • The url is not nil and the url is the same
  • The application name and title are the same, eg. Slack + general discussion != Slack + funny memes

func (*ApplicationUsage) TableName

func (a *ApplicationUsage) TableName() string

type ApplicationUsageTags

type ApplicationUsageTags struct {
	ID      int64  `gorm:"primaryKey;autoIncrement" json:"id"`
	Tag     string `json:"tag"`
	UsageID int64  `json:"usage_id" gorm:"index:idx_usage_id"`
}

type Classification

type Classification string

type ClassificationResponse

type ClassificationResponse struct {
	Classification               Classification       `json:"classification"`
	ClassificationSource         ClassificationSource `json:"classification_source"`
	Reasoning                    string               `json:"reasoning"`
	ConfidenceScore              float32              `json:"confidence_score"`
	DetectedProject              string               `json:"detected_project"`
	DetectedCommunicationChannel string               `json:"detected_communication_channel"`
	Tags                         []string             `json:"tags"`

	SandboxContext  string  `json:"sandbox_context"`
	SandboxResponse *string `json:"sandbox_response"`
	SandboxLogs     string  `json:"sandbox_logs"`
}

type ClassificationSource

type ClassificationSource string

type ClassifyRequest

type ClassifyRequest struct {
	AppName        string         `json:"app_name"`
	ExecutablePath string         `json:"executable_path"`
	Hostname       string         `json:"hostname"`
	URL            string         `json:"url"`
	Classification Classification `json:"classification"`
}

type DayInsights

type DayInsights struct {
	ProductivityScore            ProductivityScore
	ProductivityPerHourBreakdown ProductivityPerHourBreakdown
}

type ExecutionLogType added in v0.0.21

type ExecutionLogType string
const (
	ExecutionLogTypeClassification  ExecutionLogType = "classification"
	ExecutionLogTypeTerminationMode ExecutionLogType = "termination_mode"
)

type GetUsageListOptions

type GetUsageListOptions struct {
	Date            *time.Time
	Page            *int
	PageSize        *int
	StartedAt       *time.Time
	EndedAt         *time.Time
	TerminationMode *TerminationMode
}

type IdlePeriod

type IdlePeriod struct {
	ID              int64  `gorm:"primaryKey;autoIncrement"`
	StartedAt       int64  `json:"started_at"`
	EndedAt         *int64 `json:"end_at" gorm:"index:idx_ended_at"`
	DurationSeconds *int   `json:"duration_seconds"`
	Reason          string `json:"reason"`
}

func (*IdlePeriod) TableName

func (i *IdlePeriod) TableName() string

type MetaData

type MetaData struct {
	Property string
	Content  string
}

type Option

type Option func(*Service)

Option is a function that configures a Service.

func WithAppBlocker

func WithAppBlocker(appBlocker func(appName, title, reason string, tags []string, browserURL *string)) Option

WithAppBlocker configures the Service with a function to call when an application is blocked.

func WithGenaiClient

func WithGenaiClient(genaiClient *genai.Client) Option

WithGenaiClient configures the Service with a GenaiClient interface to allow using the Genai client.

func WithProtectionPaused

func WithProtectionPaused(onProtectionPaused func(pause ProtectionPause)) Option

WithProtectionPaused configures the Service with a function to call when protection is paused.

func WithProtectionResumed

func WithProtectionResumed(onProtectionResumed func(pause ProtectionPause)) Option

WithProtectionResumed configures the Service with a function to call when protection is resumed.

func WithSettingsService

func WithSettingsService(settingsService *settings.Service) Option

WithSettingsService configures the Service with a SettingsService interface to allow accessing settings from the database.

type PauseRequets

type PauseRequets struct {
	DurationSeconds int    `json:"duration_seconds"`
	Reason          string `json:"reason"`
}

type ProductivityPerHourBreakdown

type ProductivityPerHourBreakdown map[time.Time]ProductivityScore

type ProductivityScore

type ProductivityScore struct {
	ProductiveSeconds  int
	DistractiveSeconds int
	OtherSeconds       int
	ProductivityScore  int
}

type ProtectionPause

type ProtectionPause struct {
	ID                       int64  `gorm:"primaryKey;autoIncrement" json:"id"`
	RequestedDurationSeconds int    `json:"requested_duration_seconds"`
	ActualDurationSeconds    int    `json:"actual_duration_seconds"`
	ResumedAt                int64  `json:"resumed_at"`
	ResumedReason            string `json:"resumed_reason"`
	CreatedAt                int64  `json:"created_at"`
	Reason                   string `json:"reason"`
}

func (*ProtectionPause) TableName

func (p *ProtectionPause) TableName() string

type ProtectionWhitelist

type ProtectionWhitelist struct {
	ID             int64  `gorm:"primaryKey;autoIncrement" json:"id"`
	ExecutablePath string `gorm:"uniqueIndex:idx_allow_usage_identity" json:"executable_path"`
	Hostname       string `gorm:"uniqueIndex:idx_allow_usage_identity" json:"hostname"`
	URL            string `gorm:"uniqueIndex:idx_allow_usage_identity" json:"url"`
	ExpiresAt      int64  `json:"expires_at"` // nil = allow indefinitely, otherwise Unix timestamp
}

func (*ProtectionWhitelist) TableName

func (p *ProtectionWhitelist) TableName() string

type SandboxExecutionLog

type SandboxExecutionLog struct {
	ID         int64   `gorm:"primaryKey;autoIncrement" json:"id"`
	Context    string  `json:"context" gorm:"type:text;nullable"`
	Response   *string `json:"response" gorm:"type:text;nullable"`
	Logs       string  `json:"logs" gorm:"type:text;nullable"`
	CreatedAt  int64   `json:"created_at" gorm:"index:idx_created_at"`
	FinishedAt *int64  `json:"finished_at" gorm:"index:idx_finished_at;nullable"`
	Error      *string `json:"error" gorm:"type:text;nullable"`
	Type       string  `json:"type" gorm:"index:idx_type"`
}

type Service

type Service struct {

	// channel to receive usage updates
	UsageUpdates chan *ApplicationUsage
	// contains filtered or unexported fields
}

func NewService

func NewService(ctx context.Context, db *gorm.DB, options ...Option) (*Service, error)

func (*Service) CalculateTerminationMode

func (s *Service) CalculateTerminationMode(ctx context.Context, appUsage *ApplicationUsage) (TerminationDecision, error)

CalculateTerminationMode determines whether an application or website should be blocked, allowed, or paused based on classification, custom rules, protection status, and whitelist entries.

This function evaluates multiple factors in order of priority: 1. Custom rules (if configured) - highest priority 2. Classification - non-distracting usage is always allowed 3. Protection pause status - if protection is paused, usage is allowed 4. Whitelist entries - temporarily whitelisted bundle ID/hostname combinations are allowed 5. Default blocking - distracting usage is blocked when protection is active

Parameters:

  • bundleID: The application bundle identifier (e.g., "com.example.app")
  • hostname: The website hostname (e.g., "example.com") - empty string for non-browser apps
  • domain: The domain name extracted from the URL
  • url: The full URL being accessed
  • classification: The classification result indicating whether the usage is distracting
  • terminationMode: The requested termination mode (may be overridden by custom rules)

Returns:

  • TerminationDecision: A decision containing the mode (Allow/Block/Paused), reasoning, and source
  • error: Database error if protection status or whitelist lookup fails

func (*Service) ClassifyCustomRules

func (s *Service) ClassifyCustomRules(ctx context.Context, appName string, executablePath string, url *string, nowTime *time.Time) (*ClassificationResponse, error)

func (*Service) ClassifyCustomRulesWithSandbox

func (s *Service) ClassifyCustomRulesWithSandbox(ctx context.Context, sandboxCtx sandboxContext) (*ClassificationResponse, error)

func (*Service) ClassifyWithLLM

func (s *Service) ClassifyWithLLM(ctx context.Context, appName, title, executablePath string, url *string) (*ClassificationResponse, error)

func (*Service) GetDayInsights

func (s *Service) GetDayInsights(date time.Time) (DayInsights, error)

func (*Service) GetPauseHistory

func (s *Service) GetPauseHistory(days int) ([]ProtectionPause, error)

GetPauseHistory retrieves the history of protection pauses within the specified number of days.

Parameters:

  • days: The number of days to look back (e.g., 7 for one week)

Returns:

  • []ProtectionPause: A slice of pause records ordered by creation time (newest first)
  • error: Database error if the query fails

func (*Service) GetProtectionStatus

func (s *Service) GetProtectionStatus() (ProtectionPause, error)

GetProtectionStatus retrieves the current protection pause status.

It queries for an active ProtectionPause record where ResumedAt is greater than the current time (indicating the pause is still active and hasn't been resumed yet). When a pause is created, ResumedAt is set to a future timestamp representing when the pause should automatically expire. When manually resumed, ResumedAt is updated to the current time, making it no longer match this query.

Returns:

  • ProtectionPause: The active pause record if protection is currently paused, or an empty ProtectionPause (ID == 0) if protection is active (not paused)
  • error: Database error if the query fails

func (*Service) GetSandboxExecutionLogs added in v0.0.21

func (s *Service) GetSandboxExecutionLogs(logType string, search string, page, pageSize int) ([]SandboxExecutionLog, error)

GetSandboxExecutionLogs retrieves paginated sandbox execution logs from the database. It supports fuzzy search on context and response fields, and filtering by log type. Only returns logs from the last 7 days.

func (*Service) GetUsageList

func (s *Service) GetUsageList(options GetUsageListOptions) ([]ApplicationUsage, error)

GetUsageList returns a list of application usages for the given date and pagination options

Parameters:

  • options: GetUsageListOptions
  • Date: The date to get usages for - useful for detailed analysis of a specific day usage
  • Page: The page number to get
  • PageSize: The number of usages per page

Returns:

  • []ApplicationUsage: The list of application usages

func (*Service) GetWhitelist

func (s *Service) GetWhitelist() ([]ProtectionWhitelist, error)

GetWhitelist returns all active whitelist entries that haven't expired.

Returns:

  • []ProtectionWhitelist: A slice of active whitelist entries
  • error: Database error if the query fails

func (*Service) IdleChanged

func (s *Service) IdleChanged(ctx context.Context, isIdle bool) error

IdleChanged is called when the idle state of the user changes (e.g. user starts or stops using the computer)

func (*Service) PauseProtection

func (s *Service) PauseProtection(durationSeconds int, reason string) (ProtectionPause, error)

PauseProtection temporarily disables focus protection for the specified duration.

The function starts a background goroutine that automatically resumes protection after the duration expires. The pause state is persisted to the database, allowing the application to recover pause state across restarts.

Parameters:

  • duration: The duration to pause protection (must be > 0)

Returns:

  • error: Returns an error if protection is already paused

Side effects:

  • Creates a ProtectionPause record in the database
  • Emits a state update via the state channel
  • Spawns a goroutine that calls ResumeProtection after the duration

func (*Service) RegisterHTTPHandlers

func (s *Service) RegisterHTTPHandlers(r *chi.Mux)

func (*Service) RemoveWhitelist

func (s *Service) RemoveWhitelist(id int64) error

RemoveWhitelist removes a whitelist entry by ID.

Parameters:

  • id: The ID of the whitelist entry to remove

Returns:

  • error: Database error if the deletion fails

func (*Service) ResumeProtection

func (s *Service) ResumeProtection(reason string) (ProtectionPause, error)

ResumeProtection re-enables focus protection and records the reason for resumption.

This function is called either automatically when a pause duration expires, or manually by the user to end a pause early. The reason is persisted to the database for auditing and analytics purposes.

Parameters:

  • reason: A human-readable explanation for why protection was resumed (e.g., "protection paused for 5m0s expired" or "user manually resumed")

Returns:

  • error: Returns an error if protection is not currently paused

Side effects:

  • Updates the ProtectionPause record in the database with ResumedAt timestamp
  • Clears the pause state and emits a state update via the state channel

func (*Service) TitleChanged

func (s *Service) TitleChanged(ctx context.Context, executablePath, windowTitle, appName, icon string, bundleID, url *string) error

TitleChanged is called when the title of the current application changes, whether it's a new application or the same application title has changed

func (*Service) Whitelist

func (s *Service) Whitelist(executablePath string, hostname string, duration time.Duration) error

Whitelist temporarily allows a specific blocked usage (by bundle ID and hostname) for the specified duration.

This function creates a ProtectionWhitelist entry that allows the specified application or website to bypass focus protection for a limited time. This enables users to temporarily access blocked content without pausing all protection. The whitelist entry is persisted to the database and can be checked during termination decision evaluation.

Parameters:

  • bundleID: The application bundle identifier (e.g., "com.example.app")
  • hostname: The website hostname (e.g., "example.com") - empty string for non-browser apps
  • duration: The duration to allow the usage (defaults to 1 hour if 0)

Returns:

  • error: Database error if the whitelist entry creation fails

Side effects:

  • Creates a ProtectionWhitelist record in the database with expiration timestamp

type TerminationDecision

type TerminationDecision struct {
	Mode      TerminationMode
	Reasoning string
	Source    TerminationModeSource
}

type TerminationMode

type TerminationMode string

type TerminationModeSource

type TerminationModeSource string

type UnpauseRequest

type UnpauseRequest struct {
	Reason string `json:"reason"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL