appmem 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appmem-0.1.0/LICENSE +19 -0
- appmem-0.1.0/PKG-INFO +136 -0
- appmem-0.1.0/README.md +112 -0
- appmem-0.1.0/pyproject.toml +119 -0
- appmem-0.1.0/pyproject.toml.orig +89 -0
- appmem-0.1.0/src/appmem/__init__.py +7 -0
- appmem-0.1.0/src/appmem/__main__.py +14 -0
- appmem-0.1.0/src/appmem/cli.py +646 -0
- appmem-0.1.0/src/appmem/collect.py +870 -0
- appmem-0.1.0/src/appmem/command_name.py +203 -0
- appmem-0.1.0/src/appmem/fmt.py +215 -0
- appmem-0.1.0/src/appmem/naming.py +186 -0
- appmem-0.1.0/src/appmem/render.py +190 -0
- appmem-0.1.0/src/appmem/report.py +290 -0
- appmem-0.1.0/src/appmem/schema.py +853 -0
- appmem-0.1.0/src/appmem/theme.py +219 -0
- appmem-0.1.0/src/appmem/ui/__init__.py +1 -0
- appmem-0.1.0/src/appmem/ui/app.py +192 -0
- appmem-0.1.0/src/appmem/ui/header.py +519 -0
- appmem-0.1.0/src/appmem/ui/layout.py +82 -0
- appmem-0.1.0/src/appmem/ui/process_rows.py +303 -0
- appmem-0.1.0/src/appmem/ui/rows.py +167 -0
- appmem-0.1.0/src/appmem/ui/screens/__init__.py +1 -0
- appmem-0.1.0/src/appmem/ui/screens/help.py +318 -0
- appmem-0.1.0/src/appmem/ui/screens/main.py +924 -0
- appmem-0.1.0/src/appmem/ui/screens/processes.py +950 -0
- appmem-0.1.0/src/appmem/ui/table.py +155 -0
- appmem-0.1.0/src/appmem/ui/table_order.py +35 -0
- appmem-0.1.0/src/appmem/ui/theme_picker.py +169 -0
- appmem-0.1.0/src/appmem/writeback.py +56 -0
appmem-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 Damian Pala
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
14
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
15
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
16
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
17
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
18
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
|
19
|
+
OR OTHER DEALINGS IN THE SOFTWARE.
|
appmem-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: appmem
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Live terminal view of RAM and swap usage per application, not per process
|
|
5
|
+
Keywords: ram,swap,memory,cgroup,systemd,tui,monitoring,linux
|
|
6
|
+
Author: Damian Pala
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: System :: Monitoring
|
|
18
|
+
Requires-Dist: textual>=8.2.8
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Project-URL: Homepage, https://github.com/DamianPala/appmem
|
|
21
|
+
Project-URL: Repository, https://github.com/DamianPala/appmem
|
|
22
|
+
Project-URL: Issues, https://github.com/DamianPala/appmem/issues
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# appmem
|
|
26
|
+
|
|
27
|
+
Find out which apps are eating your RAM and swap. Live, in the terminal, one row per app.
|
|
28
|
+
|
|
29
|
+
The laptop starts swapping, the fan spins up, and `htop` shows forty processes called `chrome`, thirty called `node` and something called `Isolated Web Co`.
|
|
30
|
+
appmem shows the same memory as the apps you actually opened: Chrome, Firefox, VS Code, your terminal, each with its RAM, its swap and how much it grew since you started looking.
|
|
31
|
+
The header tells you whether the swapping is a problem at all, and one key opens the processes behind any row.
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
You can also skip the reading and hand the job to an AI agent.
|
|
36
|
+
Paste this into Claude Code, Codex or any agent that runs shell commands:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Install appmem (uv tool install appmem), read
|
|
40
|
+
https://raw.githubusercontent.com/DamianPala/appmem/main/skills/appmem/SKILL.md
|
|
41
|
+
and tell me what is eating my memory and what to close.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
It installs appmem, reads the numbers the way the skill file describes and tells you what to close.
|
|
45
|
+
What the agent gets is in [For agents](#for-agents).
|
|
46
|
+
|
|
47
|
+
Reach for it when:
|
|
48
|
+
|
|
49
|
+
- the machine got slow and you want the culprit, not a process list;
|
|
50
|
+
- swap is full and you want to know whether that matters right now;
|
|
51
|
+
- a "terminal" holds 17 GiB and you want to know what is really running inside it;
|
|
52
|
+
- you want to watch one app grow while you use it.
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
uv tool install appmem
|
|
58
|
+
appmem
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
No root, no config file.
|
|
62
|
+
From a checkout, `uv run appmem`.
|
|
63
|
+
|
|
64
|
+
You need Linux with systemd and a desktop that starts apps as systemd units (KDE Plasma and GNOME do), on cgroup v2, which current distributions use by default.
|
|
65
|
+
Python 3.12 or newer; uv fetches it for you.
|
|
66
|
+
Kernel 5.10 or newer; the zswap figures need 5.19 and the Pressure line needs pressure tracking (PSI) switched on in the kernel, without them those parts stay off and the rest works.
|
|
67
|
+
|
|
68
|
+
## Using it
|
|
69
|
+
|
|
70
|
+
The main view sorts by TOTAL (RAM + swap).
|
|
71
|
+
Press the first letter of a column (`r`, `s`, `t`) or click a header to sort by something else.
|
|
72
|
+
The Pressure figure in the header tells you whether memory is a problem right now: `none` with a full swap only means idle pages were moved out of the way, `some` or `high` means programs are waiting for memory.
|
|
73
|
+
|
|
74
|
+
`Enter` on an app shows its processes, their age and the systemd unit each one lives in.
|
|
75
|
+
The bottom line has the command ready for the selected row, for example `systemctl --user stop 'app-firefox.service'` or `kill 41233`.
|
|
76
|
+
|
|
77
|
+
Everything you start from a terminal counts as the terminal.
|
|
78
|
+
Press `g` in the process view to group by command.
|
|
79
|
+
That is how a "terminal holding 17 GiB" turns out to be eighteen `claude` processes plus the terminal itself, running for 86 days with 3.4 GiB in swap.
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
ΔSWAP and ΔRAM show how each app grew or shrank since you started appmem (`b` resets the baseline).
|
|
84
|
+
`x` adds system services, `c` shows the CACHE column.
|
|
85
|
+
|
|
86
|
+
`T` opens a theme panel with a live preview: Textual's built-in themes plus `terminal-dark` and `terminal-light`, which use your terminal's own colours.
|
|
87
|
+
The theme you keep is saved to `~/.config/appmem/config.toml`; `appmem --theme NAME` or `APPMEM_THEME` override it for one run.
|
|
88
|
+
|
|
89
|
+

|
|
90
|
+
|
|
91
|
+
`?` inside the app explains every number and lists the keys; `appmem --help` has the same list plus the options.
|
|
92
|
+
|
|
93
|
+
## How to read the numbers
|
|
94
|
+
|
|
95
|
+
RAM is what the app is using right now.
|
|
96
|
+
SWAP is what the system moved out of RAM to make room: onto the disk or, with zswap, into a compressed corner of RAM.
|
|
97
|
+
TOTAL is RAM + SWAP, one number to sort by.
|
|
98
|
+
Closing the app gives you back less than that: memory shared with other apps stays, and freed swap is mostly space on the disk, not RAM.
|
|
99
|
+
CACHE (press `c`) is file data the kernel keeps around because something read or wrote it recently.
|
|
100
|
+
It is not part of RAM or TOTAL: the kernel can drop it when it needs the space, and an app that just read a big file would otherwise look like a memory hog.
|
|
101
|
+
The rows don't add up to the header, because system services, virtual machines, containers and other users hold the rest.
|
|
102
|
+
|
|
103
|
+
## For agents
|
|
104
|
+
|
|
105
|
+
appmem is made to be driven by an AI agent as much as by you; the prompt at the top is all it needs.
|
|
106
|
+
The agent gets the same data as the TUI as JSON, and [skills/appmem/SKILL.md](https://github.com/DamianPala/appmem/blob/main/skills/appmem/SKILL.md) tells it how to read it: pressure against swap, what hides inside a terminal, what to recommend.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
appmem snapshot [--system] [--limit N] [--json]
|
|
110
|
+
appmem app NAME [--scope user|system] [--limit N] [--json]
|
|
111
|
+
appmem schema [COMMAND]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`snapshot` covers the machine and every app, `app NAME` one app's units, processes and commands.
|
|
115
|
+
Both print text on a terminal and JSON when piped; `--json` forces JSON.
|
|
116
|
+
`appmem schema` describes the commands, flags, output fields and exit codes as JSON.
|
|
117
|
+
Every error is one JSON object on the last line of stderr with a stable `kind` such as `not_found`; exit code 1 is a runtime failure, 2 an invalid call.
|
|
118
|
+
Bare `appmem` without a terminal exits 1 and points to `appmem snapshot`.
|
|
119
|
+
|
|
120
|
+
## Cost
|
|
121
|
+
|
|
122
|
+
Reading the counters once a second takes about 1 % of one CPU core.
|
|
123
|
+
The live view takes 4 to 12 % of one core on a busy desktop, more with a tall terminal and many apps.
|
|
124
|
+
Refreshing every two seconds instead of every second (`appmem -i 2`) cuts that in half.
|
|
125
|
+
|
|
126
|
+
## Development
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
uv run ruff check && uv run ruff format --check && uv run pyright && uv run pytest
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The screenshots come from fixture data, never a real machine; regenerate them with `uv run python scripts/screenshots.py`.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
appmem-0.1.0/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# appmem
|
|
2
|
+
|
|
3
|
+
Find out which apps are eating your RAM and swap. Live, in the terminal, one row per app.
|
|
4
|
+
|
|
5
|
+
The laptop starts swapping, the fan spins up, and `htop` shows forty processes called `chrome`, thirty called `node` and something called `Isolated Web Co`.
|
|
6
|
+
appmem shows the same memory as the apps you actually opened: Chrome, Firefox, VS Code, your terminal, each with its RAM, its swap and how much it grew since you started looking.
|
|
7
|
+
The header tells you whether the swapping is a problem at all, and one key opens the processes behind any row.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
You can also skip the reading and hand the job to an AI agent.
|
|
12
|
+
Paste this into Claude Code, Codex or any agent that runs shell commands:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Install appmem (uv tool install appmem), read
|
|
16
|
+
https://raw.githubusercontent.com/DamianPala/appmem/main/skills/appmem/SKILL.md
|
|
17
|
+
and tell me what is eating my memory and what to close.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
It installs appmem, reads the numbers the way the skill file describes and tells you what to close.
|
|
21
|
+
What the agent gets is in [For agents](#for-agents).
|
|
22
|
+
|
|
23
|
+
Reach for it when:
|
|
24
|
+
|
|
25
|
+
- the machine got slow and you want the culprit, not a process list;
|
|
26
|
+
- swap is full and you want to know whether that matters right now;
|
|
27
|
+
- a "terminal" holds 17 GiB and you want to know what is really running inside it;
|
|
28
|
+
- you want to watch one app grow while you use it.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
uv tool install appmem
|
|
34
|
+
appmem
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
No root, no config file.
|
|
38
|
+
From a checkout, `uv run appmem`.
|
|
39
|
+
|
|
40
|
+
You need Linux with systemd and a desktop that starts apps as systemd units (KDE Plasma and GNOME do), on cgroup v2, which current distributions use by default.
|
|
41
|
+
Python 3.12 or newer; uv fetches it for you.
|
|
42
|
+
Kernel 5.10 or newer; the zswap figures need 5.19 and the Pressure line needs pressure tracking (PSI) switched on in the kernel, without them those parts stay off and the rest works.
|
|
43
|
+
|
|
44
|
+
## Using it
|
|
45
|
+
|
|
46
|
+
The main view sorts by TOTAL (RAM + swap).
|
|
47
|
+
Press the first letter of a column (`r`, `s`, `t`) or click a header to sort by something else.
|
|
48
|
+
The Pressure figure in the header tells you whether memory is a problem right now: `none` with a full swap only means idle pages were moved out of the way, `some` or `high` means programs are waiting for memory.
|
|
49
|
+
|
|
50
|
+
`Enter` on an app shows its processes, their age and the systemd unit each one lives in.
|
|
51
|
+
The bottom line has the command ready for the selected row, for example `systemctl --user stop 'app-firefox.service'` or `kill 41233`.
|
|
52
|
+
|
|
53
|
+
Everything you start from a terminal counts as the terminal.
|
|
54
|
+
Press `g` in the process view to group by command.
|
|
55
|
+
That is how a "terminal holding 17 GiB" turns out to be eighteen `claude` processes plus the terminal itself, running for 86 days with 3.4 GiB in swap.
|
|
56
|
+
|
|
57
|
+

|
|
58
|
+
|
|
59
|
+
ΔSWAP and ΔRAM show how each app grew or shrank since you started appmem (`b` resets the baseline).
|
|
60
|
+
`x` adds system services, `c` shows the CACHE column.
|
|
61
|
+
|
|
62
|
+
`T` opens a theme panel with a live preview: Textual's built-in themes plus `terminal-dark` and `terminal-light`, which use your terminal's own colours.
|
|
63
|
+
The theme you keep is saved to `~/.config/appmem/config.toml`; `appmem --theme NAME` or `APPMEM_THEME` override it for one run.
|
|
64
|
+
|
|
65
|
+

|
|
66
|
+
|
|
67
|
+
`?` inside the app explains every number and lists the keys; `appmem --help` has the same list plus the options.
|
|
68
|
+
|
|
69
|
+
## How to read the numbers
|
|
70
|
+
|
|
71
|
+
RAM is what the app is using right now.
|
|
72
|
+
SWAP is what the system moved out of RAM to make room: onto the disk or, with zswap, into a compressed corner of RAM.
|
|
73
|
+
TOTAL is RAM + SWAP, one number to sort by.
|
|
74
|
+
Closing the app gives you back less than that: memory shared with other apps stays, and freed swap is mostly space on the disk, not RAM.
|
|
75
|
+
CACHE (press `c`) is file data the kernel keeps around because something read or wrote it recently.
|
|
76
|
+
It is not part of RAM or TOTAL: the kernel can drop it when it needs the space, and an app that just read a big file would otherwise look like a memory hog.
|
|
77
|
+
The rows don't add up to the header, because system services, virtual machines, containers and other users hold the rest.
|
|
78
|
+
|
|
79
|
+
## For agents
|
|
80
|
+
|
|
81
|
+
appmem is made to be driven by an AI agent as much as by you; the prompt at the top is all it needs.
|
|
82
|
+
The agent gets the same data as the TUI as JSON, and [skills/appmem/SKILL.md](https://github.com/DamianPala/appmem/blob/main/skills/appmem/SKILL.md) tells it how to read it: pressure against swap, what hides inside a terminal, what to recommend.
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
appmem snapshot [--system] [--limit N] [--json]
|
|
86
|
+
appmem app NAME [--scope user|system] [--limit N] [--json]
|
|
87
|
+
appmem schema [COMMAND]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`snapshot` covers the machine and every app, `app NAME` one app's units, processes and commands.
|
|
91
|
+
Both print text on a terminal and JSON when piped; `--json` forces JSON.
|
|
92
|
+
`appmem schema` describes the commands, flags, output fields and exit codes as JSON.
|
|
93
|
+
Every error is one JSON object on the last line of stderr with a stable `kind` such as `not_found`; exit code 1 is a runtime failure, 2 an invalid call.
|
|
94
|
+
Bare `appmem` without a terminal exits 1 and points to `appmem snapshot`.
|
|
95
|
+
|
|
96
|
+
## Cost
|
|
97
|
+
|
|
98
|
+
Reading the counters once a second takes about 1 % of one CPU core.
|
|
99
|
+
The live view takes 4 to 12 % of one core on a busy desktop, more with a tall terminal and many apps.
|
|
100
|
+
Refreshing every two seconds instead of every second (`appmem -i 2`) cuts that in half.
|
|
101
|
+
|
|
102
|
+
## Development
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
uv run ruff check && uv run ruff format --check && uv run pyright && uv run pytest
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The screenshots come from fixture data, never a real machine; regenerate them with `uv run python scripts/screenshots.py`.
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "appmem"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Live terminal view of RAM and swap usage per application, not per process"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
keywords = [
|
|
10
|
+
"ram",
|
|
11
|
+
"swap",
|
|
12
|
+
"memory",
|
|
13
|
+
"cgroup",
|
|
14
|
+
"systemd",
|
|
15
|
+
"tui",
|
|
16
|
+
"monitoring",
|
|
17
|
+
"linux",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Environment :: Console",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Intended Audience :: System Administrators",
|
|
24
|
+
"Operating System :: POSIX :: Linux",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Topic :: System :: Monitoring",
|
|
29
|
+
]
|
|
30
|
+
dependencies = ["textual>=8.2.8"]
|
|
31
|
+
|
|
32
|
+
[[project.authors]]
|
|
33
|
+
name = "Damian Pala"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/DamianPala/appmem"
|
|
37
|
+
Repository = "https://github.com/DamianPala/appmem"
|
|
38
|
+
Issues = "https://github.com/DamianPala/appmem/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
appmem = "appmem.__main__:main"
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = [
|
|
45
|
+
"pyright>=1.1",
|
|
46
|
+
"pytest>=8",
|
|
47
|
+
"pytest-asyncio>=1.4.0",
|
|
48
|
+
"ruff>=0.14",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["uv_build>=0.10.10,<0.11.0"]
|
|
53
|
+
build-backend = "uv_build"
|
|
54
|
+
|
|
55
|
+
[tool.ruff]
|
|
56
|
+
line-length = 100
|
|
57
|
+
target-version = "py312"
|
|
58
|
+
src = [
|
|
59
|
+
"src",
|
|
60
|
+
"tests",
|
|
61
|
+
"scripts",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint]
|
|
65
|
+
select = [
|
|
66
|
+
"E",
|
|
67
|
+
"F",
|
|
68
|
+
"I",
|
|
69
|
+
"W",
|
|
70
|
+
"N",
|
|
71
|
+
"UP",
|
|
72
|
+
"B",
|
|
73
|
+
"C4",
|
|
74
|
+
"SIM",
|
|
75
|
+
"RUF",
|
|
76
|
+
"C90",
|
|
77
|
+
"PLR0913",
|
|
78
|
+
"PLR0917",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint.mccabe]
|
|
82
|
+
max-complexity = 8
|
|
83
|
+
|
|
84
|
+
[tool.ruff.lint.pylint]
|
|
85
|
+
max-args = 8
|
|
86
|
+
max-positional-args = 5
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint.isort]
|
|
89
|
+
known-first-party = ["appmem"]
|
|
90
|
+
|
|
91
|
+
[tool.ruff.lint.per-file-ignores]
|
|
92
|
+
"scripts/*" = ["E402"]
|
|
93
|
+
|
|
94
|
+
[tool.pyright]
|
|
95
|
+
pythonVersion = "3.12"
|
|
96
|
+
typeCheckingMode = "strict"
|
|
97
|
+
include = [
|
|
98
|
+
"src",
|
|
99
|
+
"tests",
|
|
100
|
+
"scripts",
|
|
101
|
+
]
|
|
102
|
+
venvPath = "."
|
|
103
|
+
venv = ".venv"
|
|
104
|
+
|
|
105
|
+
[[tool.pyright.executionEnvironments]]
|
|
106
|
+
root = "scripts"
|
|
107
|
+
extraPaths = [
|
|
108
|
+
"tests",
|
|
109
|
+
"src",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
[tool.pytest.ini_options]
|
|
113
|
+
addopts = "--strict-markers --strict-config"
|
|
114
|
+
testpaths = ["tests"]
|
|
115
|
+
filterwarnings = ["error"]
|
|
116
|
+
asyncio_mode = "strict"
|
|
117
|
+
|
|
118
|
+
[tool.uv]
|
|
119
|
+
exclude-newer = "2026-09-25T00:00:00Z"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "appmem"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Live terminal view of RAM and swap usage per application, not per process"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
authors = [{ name = "Damian Pala" }]
|
|
10
|
+
keywords = ["ram", "swap", "memory", "cgroup", "systemd", "tui", "monitoring", "linux"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Intended Audience :: System Administrators",
|
|
16
|
+
"Operating System :: POSIX :: Linux",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Topic :: System :: Monitoring",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"textual>=8.2.8",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/DamianPala/appmem"
|
|
28
|
+
Repository = "https://github.com/DamianPala/appmem"
|
|
29
|
+
Issues = "https://github.com/DamianPala/appmem/issues"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
appmem = "appmem.__main__:main"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"pyright>=1.1",
|
|
37
|
+
"pytest>=8",
|
|
38
|
+
"pytest-asyncio>=1.4.0",
|
|
39
|
+
"ruff>=0.14",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["uv_build>=0.10.10,<0.11.0"]
|
|
44
|
+
build-backend = "uv_build"
|
|
45
|
+
|
|
46
|
+
[tool.ruff]
|
|
47
|
+
line-length = 100
|
|
48
|
+
target-version = "py312"
|
|
49
|
+
src = ["src", "tests", "scripts"]
|
|
50
|
+
|
|
51
|
+
[tool.ruff.lint]
|
|
52
|
+
select = ["E", "F", "I", "W", "N", "UP", "B", "C4", "SIM", "RUF", "C90", "PLR0913", "PLR0917"]
|
|
53
|
+
mccabe.max-complexity = 8
|
|
54
|
+
pylint.max-args = 8
|
|
55
|
+
pylint.max-positional-args = 5
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint.isort]
|
|
58
|
+
known-first-party = ["appmem"]
|
|
59
|
+
|
|
60
|
+
[tool.ruff.lint.per-file-ignores]
|
|
61
|
+
# scripts/screenshots.py fixes `sys.path` to reach tests/helpers.py before
|
|
62
|
+
# importing from it -- see the comment at that import.
|
|
63
|
+
"scripts/*" = ["E402"]
|
|
64
|
+
|
|
65
|
+
[tool.pyright]
|
|
66
|
+
pythonVersion = "3.12"
|
|
67
|
+
typeCheckingMode = "strict"
|
|
68
|
+
include = ["src", "tests", "scripts"]
|
|
69
|
+
venvPath = "."
|
|
70
|
+
venv = ".venv"
|
|
71
|
+
|
|
72
|
+
[[tool.pyright.executionEnvironments]]
|
|
73
|
+
# Only scripts/ needs tests/helpers.py on its path (see the comment at that
|
|
74
|
+
# import in scripts/screenshots.py); scoping it here, instead of a top-level
|
|
75
|
+
# extraPaths, keeps pyright resolving the installed `appmem` package for
|
|
76
|
+
# src/ and tests/ exactly as before.
|
|
77
|
+
root = "scripts"
|
|
78
|
+
extraPaths = ["tests", "src"]
|
|
79
|
+
|
|
80
|
+
[tool.pytest.ini_options]
|
|
81
|
+
addopts = "--strict-markers --strict-config"
|
|
82
|
+
testpaths = ["tests"]
|
|
83
|
+
filterwarnings = ["error"]
|
|
84
|
+
asyncio_mode = "strict"
|
|
85
|
+
|
|
86
|
+
[tool.uv]
|
|
87
|
+
# Pinned so `uv lock` resolves the same set everywhere; a user-level `exclude-newer`
|
|
88
|
+
# alone is not recorded consistently and made CI's `uv sync --locked` re-resolve.
|
|
89
|
+
exclude-newer = "2026-09-25T00:00:00Z"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""appmem: live terminal view of RAM and swap usage per application."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version
|
|
4
|
+
|
|
5
|
+
# pyproject.toml's [project] version is the single source; read it back from the
|
|
6
|
+
# installed distribution's metadata instead of duplicating it here by hand.
|
|
7
|
+
__version__ = version(__name__)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""CLI entry point (SPEC.md "Command line")."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from appmem.cli import main as _main
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
"""Run the CLI and exit with its process exit code."""
|
|
10
|
+
raise SystemExit(_main())
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if __name__ == "__main__":
|
|
14
|
+
main()
|