@aaa-sentinel/ai-usage 0.1.0 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +272 -69
  2. package/dist/cli.js +19 -3
  3. package/package.json +42 -42
package/README.md CHANGED
@@ -4,90 +4,307 @@ Reports the usage of an **individual Cursor, Claude Code, GitHub Copilot or Code
4
4
  AAA Sentinel, so a personal subscription shows which models it is spent on instead of only a
5
5
  plan percentage. The prompt, the code and the conversation stay on the laptop.
6
6
 
7
- ## Requirements
7
+ - [Who does what](#who-does-what)
8
+ - [What leaves your machine](#what-actually-leaves-your-machine)
9
+ - [Setup, step by step](#setup-step-by-step)
10
+ - [Automatic start](#automatic-start)
11
+ - [Per tool](#per-tool)
12
+ - [Reading the figures](#reading-the-figures)
13
+ - [Troubleshooting](#troubleshooting)
14
+ - [Update and remove](#update-and-remove)
15
+ - [Environment variables](#environment-variables)
8
16
 
9
- - Node.js 20 or newer.
10
- - An individual AI connection in AAA Sentinel (Cursor, Anthropic, Copilot or OpenAI) and the
11
- enrollment token it issues. The token is shown once; rotating it invalidates the previous one.
12
- - For Copilot only: the [GitHub CLI](https://cli.github.com), already signed in (`gh auth login`)
13
- to the account that holds the Copilot plan.
17
+ ## Who does what
14
18
 
15
- ## Install
19
+ **The person who manages the organization** adds an individual AI connection in AAA Sentinel
20
+ (Cursor, Anthropic for Claude Code, Copilot, or OpenAI for Codex) with the email of the person who
21
+ uses the tool. In *View connection → Usage agent* they choose **Enroll** and **Copy**: the token is
22
+ shown only once. They send it through a private channel, such as a password manager or a direct
23
+ message deleted afterwards — never a team channel, a ticket or an email with others in copy.
16
24
 
17
- ```bash
25
+ **The person who uses the tool** follows the steps below on every computer where they use it, with
26
+ the same token. No administrator rights are needed. After step 5 there is nothing to start by hand.
27
+
28
+ If the account is yours, you do both parts.
29
+
30
+ ## What actually leaves your machine
31
+
32
+ One request per day of usage, with **the day, the model and the counters** — input, output,
33
+ cache-read and cache-write tokens, and the number of turns — plus a random identifier generated
34
+ on this machine that only tells two laptops apart. Each run also asks the server which tool the
35
+ connection is for; that request carries nothing but the token.
36
+
37
+ Not the prompt, not the code, not the conversation, not your email, not project names and not the
38
+ path of a transcript. The CLI reads only the tool its connection is for: a connection enrolled for
39
+ Cursor never opens a Claude Code transcript, and `gh` is not called unless the connection is
40
+ Copilot.
41
+
42
+ The figures are not converted to money and are not added to billed or estimated spend.
43
+
44
+ ## Setup, step by step
45
+
46
+ Pick the commands for the terminal you use. Install the agent **on the same system where the AI
47
+ tool runs**: if you open Cursor or Claude Code on Windows, use a Windows terminal even if you also
48
+ have WSL.
49
+
50
+ | Terminal | How to open it |
51
+ | --- | --- |
52
+ | PowerShell (Windows) | Start → type `PowerShell` → Windows PowerShell, PowerShell 7 or a PowerShell tab in Windows Terminal. Not as administrator |
53
+ | CMD (Windows) | Start → type `cmd` → Command Prompt. Not as administrator |
54
+ | Git Bash (Windows) | Comes with Git for Windows. Start, or right-click a folder → *Open Git Bash here* |
55
+ | WSL | Your distribution from Start, or `wsl` in PowerShell. Only if the AI tool runs inside WSL |
56
+ | macOS | Applications → Utilities → Terminal, or iTerm2. zsh, bash and fish all work |
57
+ | Linux | Any terminal in your desktop session, as your own user (not root) |
58
+
59
+ ### 1. Node.js 20 or later
60
+
61
+ ```sh
62
+ node --version
63
+ npm --version
64
+ ```
65
+
66
+ The first line must start with `v20` or higher. If not:
67
+
68
+ | System | Install the LTS |
69
+ | --- | --- |
70
+ | Windows | `winget install OpenJS.NodeJS.LTS`, or the installer from nodejs.org. Then open a new terminal |
71
+ | macOS | `brew install node`, or the installer from nodejs.org |
72
+ | Linux, WSL | Many distributions ship old versions. Use [nvm](https://github.com/nvm-sh/nvm): run `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh \| bash`, open a new terminal, then `nvm install --lts`. Inside WSL, the Windows Node does not count |
73
+
74
+ ### 2. Install the agent
75
+
76
+ ```sh
18
77
  npm install -g @aaa-sentinel/ai-usage
19
78
  ```
20
79
 
21
- Save the token to a file only you can read, then pass it on **standard input**:
80
+ Check that the command exists:
81
+
82
+ | Terminal | Command |
83
+ | --- | --- |
84
+ | PowerShell | `Get-Command sentinel-usage` |
85
+ | CMD | `where sentinel-usage` |
86
+ | Git Bash, WSL, macOS, Linux | `command -v sentinel-usage` |
22
87
 
23
- ```bash
24
- sentinel-usage login < token.txt
88
+ If it is not found, **close the terminal and open a new one** — the npm folder is added to `PATH`
89
+ when the shell starts. If it is still missing:
90
+
91
+ - **Windows**: the folder printed by `npm prefix -g` must be in your user `PATH` (Settings →
92
+ System → About → Advanced system settings → Environment Variables).
93
+ - **macOS, Linux, WSL**: add it to your shell, then open a new terminal.
94
+
95
+ ```sh
96
+ # bash / zsh (use ~/.zshrc on macOS)
97
+ echo 'export PATH="$(npm prefix -g)/bin:$PATH"' >> ~/.bashrc
98
+ # fish
99
+ fish_add_path (npm prefix -g)/bin
100
+ ```
101
+
102
+ - **PowerShell says running scripts is disabled**: type `sentinel-usage.cmd` instead of
103
+ `sentinel-usage` in every command. It behaves the same.
104
+
105
+ Do not use `sudo` to install or to log in: the token and the automatic start would end up in the
106
+ root account and would not see your usage.
107
+
108
+ ### 3. The token
109
+
110
+ Get it from whoever manages the organization, or, if you manage the connection: *AI connections →
111
+ the connection's card → View connection → Usage agent → Enroll → Copy*. If a token already existed
112
+ and you do not have it, choose **Rotate token**: the previous one stops working on every computer.
113
+
114
+ Each token belongs to one connection — one person and one tool. Treat it like a password.
115
+
116
+ ### 4. Connect this computer
117
+
118
+ With the token copied to the clipboard, run the line for your terminal. The token is read from the
119
+ clipboard, so it stays out of the shell history and out of any file.
120
+
121
+ | Terminal | Command |
122
+ | --- | --- |
123
+ | PowerShell | `Get-Clipboard \| sentinel-usage login` |
124
+ | CMD | `powershell -NoProfile -Command Get-Clipboard \| sentinel-usage login` |
125
+ | Git Bash | `cat /dev/clipboard \| sentinel-usage login` |
126
+ | WSL | `powershell.exe -NoProfile -Command Get-Clipboard \| sentinel-usage login` |
127
+ | macOS | `pbpaste \| sentinel-usage login` |
128
+ | Linux (Wayland) | `wl-paste \| sentinel-usage login` (needs `wl-clipboard`) |
129
+ | Linux (X11) | `xclip -selection clipboard -o \| sentinel-usage login` (needs `xclip`) |
130
+
131
+ Expected answer (the CLI prints its messages in Spanish):
132
+
133
+ ```text
134
+ Agente instalado. El arranque subirá el uso; no hace falta lanzarlo en cada sesión.
25
135
  ```
26
136
 
27
- ```powershell
28
- Get-Content -Raw -Encoding utf8 token.txt | sentinel-usage login
137
+ `login` stores the token, installs the Cursor hook and schedules the automatic upload. If any step
138
+ fails, nothing is left installed and you can run it again.
139
+
140
+ **Without a clipboard** (for example over SSH), create `token.txt` in the current folder with the
141
+ token as its only line, then:
142
+
143
+ | Terminal | Commands |
144
+ | --- | --- |
145
+ | PowerShell | `Get-Content -Raw -Encoding utf8 token.txt \| sentinel-usage login` then `Remove-Item token.txt` |
146
+ | CMD | `sentinel-usage login < token.txt` then `del token.txt` |
147
+ | Git Bash, WSL, macOS, Linux | `sentinel-usage login < token.txt` then `rm token.txt` |
148
+
149
+ - On Windows, Notepad adds `.txt` and File Explorer hides extensions, so the file may end up as
150
+ `token.txt.txt`. Save it with the name `token` only, or check the real name with `dir`.
151
+ - On macOS, TextEdit saves rich text by default: use *Format → Make Plain Text* before saving.
152
+
153
+ The token is never accepted as an argument — it would stay in the shell history — and it is never
154
+ read from the keyboard, so it is not echoed.
155
+
156
+ ### 5. Check that it works
157
+
158
+ Use the tool for a moment (one question is enough), then upload without waiting for the next hour:
159
+
160
+ ```sh
161
+ sentinel-usage report
29
162
  ```
30
163
 
31
- Delete the file when `login` finishes. The token is never accepted as an argument — it would stay
32
- in the shell history — and it is never read from the keyboard, so it is not echoed.
164
+ ```text
165
+ Uso aceptado hasta 2026-10-16.
166
+ ```
33
167
 
34
- `login` registers a startup task: at sign-in and every hour while a session is open (Task
35
- Scheduler on Windows, `launchd` on macOS, a `systemd` user timer on Linux). That task runs
36
- `sentinel-usage report`. You do not start anything when you sit down to work.
168
+ `No hay uso nuevo que subir.` means you have not used the tool since `login`. Then:
37
169
 
38
- ## Commands
170
+ ```sh
171
+ sentinel-usage status
172
+ ```
39
173
 
40
- | Command | What it does |
174
+ ```text
175
+ agente: instalado
176
+ arranque: sí
177
+ herramienta: claude_code
178
+ último día aceptado: 2026-10-16
179
+ ```
180
+
181
+ `herramienta` is the tool this connection reads: `cursor`, `claude_code`, `github_copilot` or
182
+ `codex`. In AAA Sentinel the connection's card no longer says *Silent agent* and shows the last
183
+ day, the turns and the tokens.
184
+
185
+ ## Automatic start
186
+
187
+ `login` schedules `sentinel-usage report` at sign-in and every hour while a session is open.
188
+
189
+ | System | What is created |
41
190
  | --- | --- |
42
- | `sentinel-usage login` | Stores the token read from standard input, installs the Cursor hook and registers the startup task. If any step fails, nothing is left installed |
43
- | `sentinel-usage report` | Uploads the usage that is new since the last accepted day. Run by the startup task; safe to run by hand |
44
- | `sentinel-usage status` | Says whether the agent and the startup task are installed, which tool this connection reports, and the last accepted day. It does not print the token |
45
- | `sentinel-usage logout` | Removes the startup task, the Cursor hook and the token from this machine |
191
+ | Windows | Two Task Scheduler tasks, `AAA Sentinel AI usage` and `AAA Sentinel AI usage logon`, for your user only, without administrator rights. They run while you are signed in |
192
+ | macOS | A LaunchAgent, `com.aaa-sentinel.ai-usage`, in `~/Library/LaunchAgents`. Run `login` from the Terminal of your session, not over SSH |
193
+ | Linux | A systemd user timer, `aaa-sentinel-ai-usage.timer`. Needs a session with a systemd user instance |
194
+ | WSL | Same as Linux, and WSL needs systemd enabled (below). Runs while WSL is open |
195
+
196
+ To enable systemd in WSL, add this to `/etc/wsl.conf` (with `sudo`) and run `wsl --shutdown` from
197
+ PowerShell:
198
+
199
+ ```ini
200
+ [boot]
201
+ systemd=true
202
+ ```
203
+
204
+ `sentinel-usage status` says `arranque: sí` when the automatic start is in place.
205
+
206
+ ## Per tool
207
+
208
+ - **Cursor.** `login` adds a hook to `~/.cursor/hooks.json` that writes one small file per turn to
209
+ a local spool. If Cursor was open, quit it completely and reopen it. If the hook carries token
210
+ counters they are reported per model; the stored input excludes cache, which is sent separately.
211
+ If the counters are missing, the turn is counted and no token number is invented.
212
+ - **Claude Code.** Nothing to configure. The usage counters of the session files in
213
+ `~/.claude/projects` (or under `CLAUDE_CONFIG_DIR`) are read — Claude Code in the terminal, VS
214
+ Code or JetBrains, as long as it runs on this computer with this user. If Claude Code runs in WSL,
215
+ a dev container or a remote machine over SSH, install the agent there. A cost figure that
216
+ sometimes comes with the session is not uploaded. A turn here is one call to the model, so a
217
+ reply that uses tools counts several.
218
+ - **GitHub Copilot.** Needs the [GitHub CLI](https://cli.github.com) signed in to the account that
219
+ holds the Copilot plan: `gh auth login`, then `gh auth status` must show that account
220
+ (`winget install GitHub.cli` on Windows, `brew install gh` on macOS). Premium requests by model
221
+ are read through `gh`; GitHub does not report tokens. This is account usage, not device usage, so
222
+ two laptops do not double it. If `gh` answers 401 or 403, an empty row is not written.
223
+ - **Codex.** Session counters, only when Codex is signed in with the ChatGPT subscription
224
+ (`codex login` → sign in with ChatGPT). If its auth file shows an API key, nothing is attributed
225
+ to the individual account: that spend belongs to the organization connection.
226
+
227
+ Each user on a computer reports **one** connection: a second `login` with another token replaces
228
+ the first. Usage from before `login` is never uploaded.
229
+
230
+ ## Reading the figures
231
+
232
+ What the organization sees on the connection's card, for the plan's current renewal period:
233
+
234
+ | Figure | Meaning |
235
+ | --- | --- |
236
+ | Turns | Calls to the model. Cursor: a chat or agent turn. Copilot: premium requests |
237
+ | Input | New tokens sent to the model, **excluding cache** |
238
+ | Cache read | Context the provider already had stored (open code, conversation, instructions) and the model reads again each turn. Usually the largest figure; each token costs a fraction of an input token |
239
+ | Cache write | New context stored for later turns. Costs about the same as, or a little more than, input |
240
+ | Output | What the model generates. The most expensive kind of token |
241
+
242
+ Coding tools resend the same context every turn and the provider serves it from cache, so a
243
+ working day can show a few thousand input tokens and millions read from cache. That is normal, not
244
+ a measurement error. Add input, cache read and cache write to see how much text the model processed.
245
+
246
+ *Silent agent* means the token exists but no usage arrived this period — not a zero. Usage arrives
247
+ hourly while the person is signed in; if the computer was off, it arrives when it is switched on
248
+ again. An Anthropic connection measures Claude Code, not the claude.ai chat; an OpenAI connection
249
+ measures Codex, not the ChatGPT chat.
250
+
251
+ ## Troubleshooting
252
+
253
+ | You see | What to do |
254
+ | --- | --- |
255
+ | `sentinel-usage` not recognized / `command not found` | Open a new terminal. Then see step 2 about `PATH`. On Windows you can run the full path: the `npm prefix -g` folder plus `sentinel-usage.cmd` |
256
+ | PowerShell: *running scripts is disabled* | Use `sentinel-usage.cmd`, or `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` if your company allows it |
257
+ | PowerShell: *The '<' operator is reserved for future use* | PowerShell cannot redirect files with `<`; use the PowerShell line from step 4 |
258
+ | `EACCES` from npm on macOS/Linux | Do not use `sudo`. Install Node with nvm, or `npm config set prefix ~/.npm-global`, add `~/.npm-global/bin` to `PATH`, install again |
259
+ | `EBADENGINE`, or `SyntaxError` when running | Node is older than 20. Update it (step 1) |
260
+ | *Redirige el token a la entrada estándar…* | `login` received no token. Use a full command from step 4 |
261
+ | *El token no tiene el formato de un alta de uso.* | The clipboard or file does not hold just the token. Copy it again right before the command, or rotate a new one |
262
+ | Windows: `token.txt` not found | It was saved as `token.txt.txt`. Check with `dir` |
263
+ | Exit code `3` — *No se pudo registrar el arranque* | Windows: a company policy may block Task Scheduler, ask IT. macOS: run `login` in the Terminal of your session, not over SSH. Linux/WSL: no systemd user instance, see [Automatic start](#automatic-start). Nothing is left installed |
264
+ | Exit code `4` — *El servidor no reconoce el token* | The token was rotated or the connection was revoked or removed. Get a new token and repeat step 4 |
265
+ | *El uso de esta herramienta no corresponde a esta conexión…* | The token was enrolled for a different tool. Use the token of the connection that matches this machine's tool |
266
+ | Exit code `5` | Copilot: install `gh` and `gh auth login` to the account that holds Copilot |
267
+ | `sentinel-usage: fetch failed` | No route to `https://api.aaa-sentinel.com` on port 443: proxy or firewall. Ask IT. For npm behind a proxy: `npm config set proxy …` and `npm config set https-proxy …` |
268
+ | The card stays on *Silent agent* | No usage this period yet. Use the tool, run `sentinel-usage report` and read its message |
46
269
 
47
270
  | Exit code | Meaning |
48
271
  | --- | --- |
49
272
  | `0` | Done, including "there is no new usage to upload" |
273
+ | `1` | Unexpected error, usually the network |
50
274
  | `2` | Wrong usage: unknown command, malformed token, or a base URL that is not `https` |
51
275
  | `3` | The startup task could not be registered or removed |
52
276
  | `4` | The server did not accept a day, or no longer recognizes the token |
53
277
  | `5` | Copilot: `gh` is missing or lacks permission to read the usage |
54
278
 
55
- Messages are printed in Spanish.
279
+ ## Update and remove
56
280
 
57
- ## What actually leaves your machine
281
+ ```sh
282
+ npm install -g @aaa-sentinel/ai-usage@latest
283
+ ```
58
284
 
59
- One request per day of usage, with **the day, the model and the counters** — input, output,
60
- cache-read and cache-write tokens, and the number of turns — plus a random identifier generated
61
- on this machine that only tells two laptops apart.
285
+ No need to log in again after an update. To remove the agent, **log out first**, then uninstall —
286
+ otherwise the scheduled task keeps pointing to a program that no longer exists:
62
287
 
63
- Not the prompt, not the code, not the conversation, not your email and not the path of a
64
- transcript. The CLI reads only the tool its connection is for: a connection enrolled for Cursor
65
- never opens a Claude Code transcript, and `gh` is not called unless the connection is Copilot.
288
+ ```sh
289
+ sentinel-usage logout
290
+ npm uninstall -g @aaa-sentinel/ai-usage
291
+ ```
66
292
 
67
- The figures are not converted to money and are not added to billed or estimated spend.
293
+ Removing the agent does not delete usage already sent. If you switch Node versions with nvm, fnm or
294
+ Volta, install the package in the new version and log in again with a rotated token: the automatic
295
+ start uses the Node that `login` ran with.
68
296
 
69
- ## What is read, per tool
70
-
71
- - **Cursor.** A hook in `~/.cursor/hooks.json` writes one small file per turn to a local spool.
72
- If the hook carries token counters they are reported per model; the stored input excludes
73
- cache. If the counters are missing, the turn is counted and no token number is invented.
74
- - **Claude Code.** The usage counters of the local session files. A cost figure that sometimes
75
- comes with the session is not uploaded. A turn here is one call to the model, so a reply that
76
- uses tools counts several.
77
- - **GitHub Copilot.** Premium requests by model for the personal account, read through `gh`.
78
- GitHub does not report tokens. This is account usage, not device usage, so two laptops do not
79
- double it. The GitHub token is not read in order to send it. If `gh` answers 401 or 403, an
80
- empty row is not written.
81
- - **Codex.** Session counters, only when Codex is signed in with the ChatGPT subscription. If its
82
- auth file shows an API key, nothing is attributed to the individual account: that spend belongs
83
- to the organization connection.
84
-
85
- Usage from before `login` is never uploaded: it predates the enrollment and the server would
86
- reject it.
297
+ | Command | What it does |
298
+ | --- | --- |
299
+ | `sentinel-usage login` | Stores the token read from standard input, installs the Cursor hook and registers the startup task. If any step fails, nothing is left installed |
300
+ | `sentinel-usage report` | Uploads the usage that is new since the last accepted day. Run by the startup task; safe to run by hand |
301
+ | `sentinel-usage status` | Says whether the agent and the startup task are installed, which tool this connection reports, and the last accepted day. It does not print the token |
302
+ | `sentinel-usage logout` | Removes the startup task, the Cursor hook and the token from this machine |
87
303
 
88
304
  ## Environment variables
89
305
 
90
- None is required.
306
+ None is required. The automatic start only sees your permanent user variables on Windows; on
307
+ macOS and Linux it does not read the variables of your shell.
91
308
 
92
309
  | Variable | Meaning |
93
310
  | --- | --- |
@@ -97,23 +314,9 @@ None is required.
97
314
  | `SENTINEL_USAGE_CLAUDE_DIR` | Claude Code projects folder. Defaults to `projects` under `CLAUDE_CONFIG_DIR` or `~/.claude` |
98
315
  | `SENTINEL_USAGE_CODEX_HOME` | Codex folder. Defaults to `CODEX_HOME` or `~/.codex` |
99
316
 
100
- The token is stored in `usage.json` inside `SENTINEL_USAGE_HOME`, readable only by your user.
101
-
102
- ## Troubleshooting
103
-
104
- **`sentinel-usage` is not found after installing.** Open a new terminal: the global `npm` folder
105
- is added to `PATH` when the shell starts.
106
-
107
- **`report` exits with 4 and says the server does not recognize the token.** The token was rotated
108
- or the connection was removed. Enroll again in the portal and repeat `login` with the new token.
109
-
110
- **`report` says the usage does not belong to this connection.** The token was enrolled for a
111
- different tool than the one in use on this machine. Nothing is uploaded; enroll the token from
112
- the connection that matches the tool.
113
-
114
- **The connection shows a silent agent in the portal.** The token exists and this renewal period
115
- has no usage yet. That is not a zero — use the tool and wait for the next hourly run, or run
116
- `sentinel-usage report` by hand.
317
+ The token is stored in `usage.json` inside `SENTINEL_USAGE_HOME`. On macOS and Linux the file is
318
+ readable only by your user (mode 600); on Windows it inherits the permissions of your profile
319
+ folder.
117
320
 
118
321
  ## License
119
322
 
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { execFile } from "node:child_process";
5
- import { homedir } from "node:os";
5
+ import { homedir, userInfo } from "node:os";
6
6
  import { dirname as dirname2, join as join5 } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { promisify } from "node:util";
@@ -40,6 +40,7 @@ function createLauncher(options) {
40
40
  const command = formatCommand(args);
41
41
  const uid = options.uid ?? 0;
42
42
  const windowsCmd = join(scriptDir, "run.cmd");
43
+ const logonXml = join(scriptDir, "logon.xml");
43
44
  return {
44
45
  async install() {
45
46
  if (platform === "win32") {
@@ -53,7 +54,21 @@ ${args.map(cmdArg).join(" ")}\r
53
54
  try {
54
55
  await run(exec, "schtasks", ["/Create", "/F", "/TN", TASK_HOURLY, "/SC", "HOURLY", "/ST", "00:00", "/IT", "/TR", tr]);
55
56
  hourlyCreated = true;
56
- await run(exec, "schtasks", ["/Create", "/F", "/TN", TASK_LOGON, "/SC", "ONLOGON", "/IT", "/TR", tr]);
57
+ const user = xmlEscape(options.windowsUser ?? "");
58
+ const xml = `<?xml version="1.0" encoding="UTF-16"?>\r
59
+ <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">\r
60
+ <Triggers><LogonTrigger><Enabled>true</Enabled><UserId>${user}</UserId></LogonTrigger></Triggers>\r
61
+ <Principals><Principal id="Author"><UserId>${user}</UserId><LogonType>InteractiveToken</LogonType><RunLevel>LeastPrivilege</RunLevel></Principal></Principals>\r
62
+ <Settings><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><StopIfGoingOnBatteries>false</StopIfGoingOnBatteries></Settings>\r
63
+ <Actions Context="Author"><Exec><Command>${xmlEscape(windowsCmd)}</Command></Exec></Actions>\r
64
+ </Task>\r
65
+ `;
66
+ writeFileSync(logonXml, Buffer.from(`\uFEFF${xml}`, "utf16le"));
67
+ try {
68
+ await run(exec, "schtasks", ["/Create", "/F", "/TN", TASK_LOGON, "/XML", logonXml]);
69
+ } finally {
70
+ rmSync(logonXml, { force: true });
71
+ }
57
72
  } catch (err) {
58
73
  if (previousCmd === null && hourlyCreated) await exec("schtasks", ["/Delete", "/TN", TASK_HOURLY, "/F"]);
59
74
  if (previousCmd === null) rmSync(windowsCmd, { force: true });
@@ -1319,7 +1334,8 @@ async function main() {
1319
1334
  args: reportArgs(),
1320
1335
  homeDir: homedir(),
1321
1336
  scriptDir: dirname2(paths.configPath),
1322
- ...uid !== void 0 ? { uid } : {}
1337
+ ...uid !== void 0 ? { uid } : {},
1338
+ windowsUser: process.env.USERDOMAIN ? `${process.env.USERDOMAIN}\\${userInfo().username}` : userInfo().username
1323
1339
  });
1324
1340
  if (command === "login") {
1325
1341
  if (tokenArg) {
package/package.json CHANGED
@@ -1,42 +1,42 @@
1
- {
2
- "name": "@aaa-sentinel/ai-usage",
3
- "version": "0.1.0",
4
- "description": "Report individual Cursor, Claude Code, Copilot and Codex usage to AAA Sentinel; prompts and tokens stay on the laptop",
5
- "license": "MIT",
6
- "type": "module",
7
- "bin": {
8
- "sentinel-usage": "dist/cli.js"
9
- },
10
- "files": [
11
- "dist"
12
- ],
13
- "keywords": [
14
- "cursor",
15
- "claude-code",
16
- "github-copilot",
17
- "codex",
18
- "finops",
19
- "ai-usage"
20
- ],
21
- "publishConfig": {
22
- "access": "public"
23
- },
24
- "homepage": "https://app.aaa-sentinel.com/developer/ai-usage",
25
- "bugs": {
26
- "url": "https://app.aaa-sentinel.com/contact"
27
- },
28
- "engines": {
29
- "node": ">=20"
30
- },
31
- "scripts": {
32
- "build": "esbuild src/cli.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/cli.js --banner:js=\"#!/usr/bin/env node\" && esbuild src/hook.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/hook.js",
33
- "prepublishOnly": "npm run build",
34
- "test": "vitest run"
35
- },
36
- "devDependencies": {
37
- "@types/node": "^22.0.0",
38
- "esbuild": "^0.24.0",
39
- "typescript": "^5.7.0",
40
- "vitest": "^2.0.0"
41
- }
42
- }
1
+ {
2
+ "name": "@aaa-sentinel/ai-usage",
3
+ "version": "0.1.2",
4
+ "description": "Report individual Cursor, Claude Code, Copilot and Codex usage to AAA Sentinel; prompts and tokens stay on the laptop",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "sentinel-usage": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "keywords": [
14
+ "cursor",
15
+ "claude-code",
16
+ "github-copilot",
17
+ "codex",
18
+ "finops",
19
+ "ai-usage"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "homepage": "https://app.aaa-sentinel.com/developer/ai-usage",
25
+ "bugs": {
26
+ "url": "https://app.aaa-sentinel.com/contact"
27
+ },
28
+ "engines": {
29
+ "node": ">=20"
30
+ },
31
+ "scripts": {
32
+ "build": "esbuild src/cli.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/cli.js --banner:js=\"#!/usr/bin/env node\" && esbuild src/hook.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/hook.js",
33
+ "prepublishOnly": "npm run build",
34
+ "test": "vitest run"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.0.0",
38
+ "esbuild": "^0.24.0",
39
+ "typescript": "^5.7.0",
40
+ "vitest": "^2.0.0"
41
+ }
42
+ }