Skip to content

Commit 3965e4e

Browse files
tduyngtduyng
authored andcommitted
feat: init codeme server with tracking and stats
0 parents  commit 3965e4e

22 files changed

+1671
-0
lines changed

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
branches: [main]
7+
8+
jobs:
9+
lint:
10+
name: Lint
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: actions/setup-go@v6
15+
with:
16+
go-version: '1.25'
17+
- run: |
18+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
19+
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
20+
- run: golangci-lint run --timeout=5m
21+
- run: go vet ./...
22+
23+
test:
24+
name: Test
25+
runs-on: macos-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: actions/setup-go@v6
29+
with:
30+
go-version: '1.25'
31+
- run: go test -v -race ./...
32+
33+
build:
34+
name: Build
35+
runs-on: macos-latest
36+
needs: [lint, test]
37+
strategy:
38+
matrix:
39+
arch: [amd64, arm64]
40+
steps:
41+
- uses: actions/checkout@v4
42+
- uses: actions/setup-go@v6
43+
with:
44+
go-version: '1.25'
45+
- run: GOARCH=${{ matrix.arch }} go build -o codeme .

.github/workflows/release.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: "Semver version (e.g. 0.1.0)"
8+
required: true
9+
10+
permissions:
11+
contents: write
12+
13+
run-name: Release v${{ github.event.inputs.version }}
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Configure git
26+
run: |
27+
git config user.name "github-actions[bot]"
28+
git config user.email "github-actions[bot]@users.noreply.github.com"
29+
30+
- name: Validate version
31+
run: |
32+
VERSION="${{ github.event.inputs.version }}"
33+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
34+
echo "❌ Invalid version: $VERSION"
35+
exit 1
36+
fi
37+
38+
- name: Set up git-cliff
39+
uses: kenji-miyake/setup-git-cliff@v2
40+
41+
- name: Install just
42+
uses: extractions/setup-just@v2
43+
44+
- name: Create release tag and commit
45+
run: |
46+
VERSION="${{ github.event.inputs.version}}"
47+
echo "Creating release v$VERSION..."
48+
just tag $VERSION
49+
git push origin HEAD:main
50+
git push origin v$VERSION
51+
echo "✓ Release v$VERSION created and pushed"
52+
53+
- name: Run GoReleaser
54+
uses: goreleaser/goreleaser-action@v6
55+
with:
56+
version: "~> v2"
57+
args: release --clean
58+
env:
59+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
codeme

.golangci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
version: '2'
2+
linters:
3+
default: none
4+
enable:
5+
- govet
6+
- ineffassign
7+
- lll
8+
- makezero
9+
- misspell
10+
- staticcheck
11+
- unused
12+
- wastedassign
13+
14+
formatters:
15+
enable:
16+
- gofmt
17+
exclusions:
18+
generated: lax
19+
paths:
20+
- third_party$
21+
- builtin$
22+
- examples$

.goreleaser.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: 2
2+
3+
builds:
4+
- env:
5+
- CGO_ENABLED=0
6+
goos:
7+
- darwin
8+
goarch:
9+
- amd64
10+
- arm64
11+
ldflags:
12+
- -s -w
13+
- -X main.version={{.Version}}
14+
- -X main.commit={{.Commit}}
15+
- -X main.buildTime={{.Date}}
16+
17+
archives:
18+
- formats: [tar.gz]
19+
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
20+
21+
release:
22+
github:
23+
owner: tduyng
24+
name: codeme

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Tien Duy
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# CodeMe
2+
3+
> Zero-config coding activity tracker written in Go
4+
5+
Track your coding activity with automatic detection of projects, languages, and branches. Designed to work seamlessly with editor integrations.
6+
7+
## Installation
8+
9+
```bash
10+
# Using go install
11+
go install github.com/tduyng/codeme@latest
12+
13+
# Or build from source
14+
git clone https://github.com/tduyng/codeme
15+
cd codeme
16+
just install
17+
```
18+
19+
## Usage
20+
21+
### Quick Start
22+
23+
```bash
24+
# Show help
25+
codeme help
26+
27+
# Show version
28+
codeme version
29+
30+
# View your stats
31+
codeme stats
32+
33+
# Today's activity only
34+
codeme today
35+
36+
# List projects
37+
codeme projects
38+
39+
# JSON output (for integrations)
40+
codeme stats --json
41+
```
42+
43+
### Automatic Tracking (Recommended)
44+
45+
Use the [codeme.nvim](https://github.com/tduyng/codeme.nvim) plugin for automatic tracking in Neovim. It tracks when you:
46+
47+
- Open files
48+
- Save files
49+
- Switch back to Neovim
50+
51+
See "Integration with Editors" section below for setup.
52+
53+
### Track Activity Manually (Advanced)
54+
55+
The track command is mainly used by editor integrations. You rarely need to call it manually.
56+
57+
```bash
58+
# Track a file (called by codeme.nvim automatically)
59+
codeme track --file /path/to/file.go --lines 100
60+
61+
# Specify language manually
62+
codeme track --file /path/to/file.txt --lang plaintext --lines 50
63+
```
64+
65+
## Features
66+
67+
- Zero configuration - works out of the box
68+
- Auto-detection - project, language, and git branch
69+
- Session tracking - 15-minute idle timeout
70+
- Streak calculation - maintain your coding momentum
71+
- SQLite storage - all data stored locally
72+
- JSON API - easy integration with editors and tools
73+
- Neovim plugin - beautiful dashboard with [codeme.nvim](https://github.com/tduyng/codeme.nvim)
74+
75+
## Data Storage
76+
77+
All data is stored locally and persists across versions:
78+
79+
```
80+
~/.local/share/codeme/codeme.db
81+
```
82+
83+
## Architecture
84+
85+
```
86+
codeme/
87+
├── main.go # CLI entry point
88+
├── core/
89+
│ ├── storage.go # SQLite operations
90+
│ ├── tracker.go # Activity tracking
91+
│ ├── detector.go # Auto-detection logic
92+
│ └── stats.go # Statistics calculation
93+
└── go.mod
94+
```
95+
96+
## Development
97+
98+
### Build and Install
99+
100+
```bash
101+
# Install development version
102+
just install
103+
104+
# Run tests
105+
just test
106+
107+
# Run locally
108+
go run . stats
109+
```
110+
111+
### Integration with Editors
112+
113+
#### Neovim
114+
115+
Install [codeme.nvim](https://github.com/tduyng/codeme.nvim) for a beautiful dashboard:
116+
117+
```lua
118+
{
119+
"tduyng/codeme.nvim",
120+
dependencies = { "nvzone/volt" },
121+
config = function()
122+
require("codeme").setup()
123+
end,
124+
}
125+
```
126+
127+
The plugin automatically tracks files and provides:
128+
129+
- 3-tab dashboard - Overview, Languages, Activity
130+
- GitHub-style activity heatmap - 7 months of coding history
131+
- Language breakdown - with visual bar graphs
132+
- Streak tracking - maintain momentum
133+
- Auto-tracking - on file open, save, and focus
134+
135+
Commands:
136+
137+
- `:CodeMe` - Open dashboard
138+
- `:CodeMeTrack` - Manually track current file
139+
- `:CodeMeToday` - Show today's stats
140+
- `:CodeMeProjects` - Show project breakdown
141+
142+
#### Other Editors
143+
144+
The CLI is designed to be editor-agnostic. Integrate by calling:
145+
146+
```bash
147+
# On file save
148+
codeme track --file "$FILE_PATH" --lang "$LANGUAGE" --lines "$LINE_COUNT"
149+
150+
# Get stats (JSON format)
151+
codeme stats --json
152+
```
153+
154+
## License
155+
156+
MIT

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.0.1

cliff.toml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
[changelog]
2+
body = """
3+
{%- macro remote_url() -%}
4+
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
5+
{%- endmacro -%}
6+
7+
{% macro print_commit(commit) -%}
8+
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
9+
{% if commit.breaking %}[**breaking**] {% endif %}\
10+
{{ commit.message | upper_first }} - \
11+
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
12+
{% endmacro -%}
13+
14+
{% if version %}\
15+
{% if previous.version %}\
16+
## [{{ version | trim_start_matches(pat="v") }}]\
17+
({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
18+
{% else %}\
19+
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
20+
{% endif %}\
21+
{% else %}\
22+
## [unreleased]
23+
{% endif %}\
24+
25+
{% for group, commits in commits | group_by(attribute="group") %}
26+
### {{ group | striptags | trim | upper_first }}
27+
{% for commit in commits
28+
| filter(attribute="scope")
29+
| sort(attribute="scope") %}
30+
{{ self::print_commit(commit=commit) }}
31+
{%- endfor %}
32+
{% for commit in commits %}
33+
{%- if not commit.scope -%}
34+
{{ self::print_commit(commit=commit) }}
35+
{% endif -%}
36+
{% endfor -%}
37+
{% endfor -%}
38+
39+
{%- if github -%}
40+
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
41+
## New Contributors
42+
{% endif %}\
43+
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
44+
* @{{ contributor.username }} made their first contribution
45+
{%- if contributor.pr_number %} in \
46+
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
47+
{%- endif %}
48+
{%- endfor -%}
49+
{%- endif %}
50+
51+
"""
52+
53+
[git]
54+
conventional_commits = true
55+
filter_unconventional = true
56+
split_commits = false
57+
protect_breaking_commits = false
58+
filter_commits = false
59+
topo_order = false
60+
sort_commits = "newest"

0 commit comments

Comments
 (0)