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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 72 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A process activity tracker, it runs as a background service recording start/stop
- [How It Works](#how-it-works)
- [Usage](#usage)
- [Installation](#installation)
- [WakaTime](#wakatime)
- [WakaTime/Wakapi](#wakatimewakapi)
- [File Locations](#file-locations)
- [Current Limitations](#current-limitations)
- [Contributing & Issues](#contributing--issues)
Expand Down Expand Up @@ -91,11 +91,35 @@ sc.exe start timekeep
Get-Service -Name "timekeep"
```


Test using CLI:
```powershell
.\timekeep.exe status # Check if the service is responsive
```

##### To include shell completion:

```powershell
New-Item -Force -ItemType Directory (Split-Path $PROFILE) | Out-Null
$comp = Join-Path (Split-Path $PROFILE) 'timekeep.ps1'
timekeep completion powershell > $comp
if (-not (Select-String -Path $PROFILE -SimpleMatch $comp -Quiet)) { Add-Content $PROFILE "`n. $comp" }
. $PROFILE
```

If you encounter issues running scripts in PowerShell, bypass the ExecutionPolicy with:

```powershell
powershell -ExecutionPolicy Bypass
```

for a single terminal session, or loosen restrictions with:

```powershell
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
```


#### Linux
```bash
# Clone and build
Expand Down Expand Up @@ -158,54 +182,13 @@ Test using CLI:
timekeep status # Check if the service is responsive
```

### Shell Completion
To include Tab-completion for Shell commands, run the completion commands specific for your Shell.

**Bash**
##### To include shell completion:

```bash
timekeep completion bash | sudo tee /etc/bash_completion.d/timekeep >/dev/null
source /etc/bash_completion
```

**PowerShell**

```powershell
New-Item -Force -ItemType Directory (Split-Path $PROFILE) | Out-Null
$comp = Join-Path (Split-Path $PROFILE) 'timekeep.ps1'
timekeep completion powershell > $comp
if (-not (Select-String -Path $PROFILE -SimpleMatch $comp -Quiet)) { Add-Content $PROFILE "`n. $comp" }
. $PROFILE
```

If you encounter issues running scripts in PowerShell, bypass the ExecutionPolicy with:

```powershell
powershell -ExecutionPolicy Bypass
```

for a single terminal session, or with:

```powershell
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
```

to loosen restrictions.


**Untested** - **Zsh**
```zsh
timekeep completion zsh | sudo tee /usr/local/share/zsh/site-functions/_timekeep >/dev/null
autoload -U compinit && compinit
```

**Untested** - **Fish**
```fish
mkdir -p ~/.config/fish/completions
timekeep completion fish > ~/.config/fish/completions/timekeep.fish
# open a new fish session
```

## Uninstalling

### Windows
Expand All @@ -222,7 +205,10 @@ sudo rm /usr/local/bin/timekeepd /usr/local/bin/timekeep
sudo systemctl daemon-reload
```

## WakaTime
## WakaTime/Wakapi

### WakaTime

Timekeep now integrates with [WakaTime](https://wakatime.com), allowing users to track external program usage alongside their IDE and web-browsing stats. **Timekeep does not track activity within these programs, only when these programs are running.**

To enable WakaTime integration, users must:
Expand All @@ -231,13 +217,13 @@ To enable WakaTime integration, users must:

Enable integration through timekeep. Retrieve your API key from your [WakaTime profile settings](https://wakatime.com/settings/account). Set your WakaTime API key and wakatime-cli path either directly in the Timekeep [config](https://github.com/jms-guy/timekeep?tab=readme-ov-file#file-locations) file, or provide them through flags:

`timekeep wakatime enable --api_key "YOUR-KEY" --cli_path "wakatime-cli-PATH"`
`timekeep wakatime enable --api_key "YOUR_KEY" --cli_path "wakatime-cli_PATH"`

```json
{
"wakatime": {
"enabled": true,
"api_key": "APIKEY",
"api_key": "API_KEY",
"cli_path": "PATH",
"global_project": "PROJECT"
}
Expand All @@ -246,11 +232,11 @@ Enable integration through timekeep. Retrieve your API key from your [WakaTime p

**The wakatime-cli path must be an absolute path.**: *C:\Path\To\\.wakatime\wakatime-cli.exe*

### Complete WakaTime setup example
#### Complete WakaTime setup example

`timekeep wakatime enable --api_key YOUR-KEY --cli_path wakatime-cli-PATH`
`timekeep wakatime enable --api_key "YOUR_KEY" --cli_path "wakatime-cli_PATH"`

`timekeep add photoshop.exe --category designing --project "UI Design"`
`timekeep add photoshop.exe --category "designing" --project "UI Design"`

Check WakaTime current enabled/disabled status:

Expand All @@ -260,10 +246,10 @@ Disable integration with:

`timekeep wakatime disable`

### Categories
#### Categories
After enabling, wakatime-cli heartbeats will be sent containing tracking data for given programs. Note, that only programs added to Timekeep with a given category will have data sent to WakaTime.

`timekeep add notepad.exe --category notes`
`timekeep add notepad.exe --category "notes"`

If no category is set for a program, it will still be tracked locally, but no data for it will be sent out.

Expand All @@ -277,20 +263,44 @@ List of categories accepted(defined [here](https://github.com/wakatime/wakatime-
" \"translating\", or \"designing\".
```

### Projects
#### Projects
Timekeep has no automatic project detection for WakaTime. Users may set a global project for all programs to use in the config, or via the command:

`timekeep config --global_project "YOUR-PROJECT"`

Users can also set project variables on a per-program basis:

`timekeep add notepad.exe --category notes --project Timekeep`
`timekeep add notepad.exe --category "notes" --project "Timekeep"`

Program-set project variables will take precedence over a set Global Project. If no project variable is set via the global_project config or when adding programs, WakaTime will fall back to default "Unknown Project".

Users can update a program's category or project with the **update** command:

`timekeep update notepad.exe --category planning --project Timekeep2`
`timekeep update notepad.exe --category "planning" --project "Timekeep2"`

### Wakapi

Similar to WakaTime, users can also allow their program activity to be tracked via [Wakapi](https://github.com/muety/wakapi). The commands and structures are very similar, to enable integration you need your Wakapi API key as well as the address to your running Wakapi server, provided through either command flags or editing the config file.

`timekeep wakapi enable --api_key "YOUR_KEY" --server "127.0.0.1:3000/api"`

`timekeep wakapi disable`

`timekeep wakapi status`

```json
{
"wakapi": {
"enabled": true,
"api_key": "API_KEY",
"server": "ADDRESS",
"global_project": "PROJECT"
}
}
```

The global project variable for Wakapi can be altered manually in the config file, otherwise setting it via the `config` command will by default set it to the same value as the WakaTime global project variable.


## File Locations
- **Logs**
Expand All @@ -300,16 +310,22 @@ Users can update a program's category or project with the **update** command:
- **Config**
- **Windows**: *C:\ProgramData\Timekeep\config*
- **Linux**: *~/.config/timekeep*
- **Config struct**:
- **Config structure**:

```json
{
"wakatime": {
"enabled": true,
"api_key": "APIKEY",
"api_key": "API_KEY",
"cli_path": "PATH",
"global_project": "PROJECT"
},
"wakapi": {
"enabled": true,
"api_key": "API_KEY",
"server": "ADDRESS",
"global_project": "PROJECT"
},
"poll_interval": "1s",
"poll_grace": 3,
}
Expand Down
65 changes: 63 additions & 2 deletions cmd/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func (s *CLIService) GetVersion() error {
return nil
}

// Changes config to enable WakaTime with API key
// Changes config to enable WakaTime
func (s *CLIService) EnableWakaTime(apiKey, path string) error {
if s.Config.WakaTime.Enabled {
return nil
Expand Down Expand Up @@ -385,13 +385,63 @@ func (s *CLIService) DisableWakaTime() error {
return nil
}

// Changes config to enable Wakapi
func (s *CLIService) EnableWakapi(apiKey, server string) error {
if s.Config.Wakapi.Enabled {
return nil
}

if apiKey != "" {
s.Config.Wakapi.APIKey = apiKey
}

if s.Config.Wakapi.APIKey == "" {
return fmt.Errorf("WakaTime API key required. Use flag: --api_key <key>")
}

if server != "" {
s.Config.Wakapi.Server = server
}

if s.Config.Wakapi.Server == "" {
return fmt.Errorf("wakapi server address required. Use flag: --server <address>")
}

s.Config.Wakapi.Enabled = true

if err := s.saveAndNotify(); err != nil {
return err
}

return nil
}

// Disables Wakapi in config
func (s *CLIService) DisableWakapi() error {
if !s.Config.Wakapi.Enabled {
return nil
}

s.Config.Wakapi.Enabled = false

if err := s.saveAndNotify(); err != nil {
return err
}

return nil
}

// Set various config values
func (s *CLIService) SetConfig(cliPath, project, interval string, grace int) error {
func (s *CLIService) SetConfig(cliPath, server, project, interval string, grace int) error {
if cliPath != "" {
s.Config.WakaTime.CLIPath = cliPath
}
if server != "" {
s.Config.Wakapi.Server = server
}
if project != "" {
s.Config.WakaTime.GlobalProject = project
s.Config.Wakapi.GlobalProject = project
}
if interval != "" {
s.Config.PollInterval = interval
Expand All @@ -417,3 +467,14 @@ func (s *CLIService) StatusWakatime() error {

return nil
}

// Returns Wakapi enabled/disabled status for user
func (s *CLIService) StatusWakapi() error {
if s.Config.Wakapi.Enabled {
fmt.Println("enabled")
} else {
fmt.Println("disabled")
}

return nil
}
6 changes: 6 additions & 0 deletions cmd/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ func (s *CLIService) RootCmd() *cobra.Command {
wCmd.AddCommand(s.wakatimeEnable())
wCmd.AddCommand(s.wakatimeDisable())

wpCmd := s.wakapiIntegration()
wpCmd.AddCommand(s.wakapiStatus())
wpCmd.AddCommand(s.wakapiEnable())
wpCmd.AddCommand(s.wakapiDisable())

rootCmd.AddCommand(wCmd)
rootCmd.AddCommand(wpCmd)
rootCmd.AddCommand(s.addProgramsCmd())
rootCmd.AddCommand(s.updateCmd())
rootCmd.AddCommand(s.removeProgramsCmd())
Expand Down
Loading