aicp-tracker 1.0.3 → 1.0.5
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.
- package/bin/aicp-tracker.js +17 -4
- package/bin/setup.js +50 -17
- package/package.json +2 -2
- package/LICENSE +0 -19
package/bin/aicp-tracker.js
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const [,, cmd
|
|
4
|
+
const [,, cmd] = process.argv;
|
|
5
|
+
|
|
6
|
+
async function ensureConfigured() {
|
|
7
|
+
const config = require('../src/config');
|
|
8
|
+
const existing = (() => { try { return config.load(); } catch { return null; } })();
|
|
9
|
+
if (existing?.apiKey && existing?.vcsUrl) return;
|
|
10
|
+
// No config — run the wizard first, then continue
|
|
11
|
+
await require('./setup').main();
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
switch (cmd) {
|
|
7
|
-
case 'start':
|
|
15
|
+
case 'start':
|
|
16
|
+
ensureConfigured().then(() => require('../src/daemon').start()).catch(e => {
|
|
17
|
+
console.error('[aicp-tracker] Setup failed:', e.message);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
20
|
+
break;
|
|
8
21
|
case 'stop': require('../src/daemon').stop(); break;
|
|
9
22
|
case 'status': require('../src/daemon').status(); break;
|
|
10
|
-
case 'setup': require('./setup');
|
|
23
|
+
case 'setup': require('./setup').main().catch(e => console.error('[aicp-tracker] Setup failed:', e.message)); break;
|
|
11
24
|
case 'flush': require('../src/wal').flush(); break;
|
|
12
25
|
default:
|
|
13
26
|
console.log(`
|
|
14
27
|
aicp-tracker <command>
|
|
15
28
|
|
|
16
29
|
Commands:
|
|
17
|
-
start Start the background tracker (
|
|
30
|
+
start Start the background tracker (runs setup wizard on first use)
|
|
18
31
|
stop Stop the background tracker
|
|
19
32
|
status Show tracker status and WAL queue depth
|
|
20
33
|
setup Re-run the configuration wizard
|
package/bin/setup.js
CHANGED
|
@@ -4,23 +4,57 @@
|
|
|
4
4
|
// Runs on `npm install` (postinstall). Skipped in CI environments.
|
|
5
5
|
if (process.env.CI || process.env.npm_config_yes) process.exit(0);
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
// Skip if already fully configured (upgrade path — no prompts needed)
|
|
9
10
|
const isPostinstall = process.env.npm_lifecycle_event === 'postinstall';
|
|
10
11
|
if (isPostinstall) {
|
|
11
12
|
let existing = null;
|
|
12
13
|
try { existing = require('../src/config').load(); } catch {}
|
|
13
|
-
if (existing?.apiKey && existing?.vcsUrl)
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (existing?.apiKey && existing?.vcsUrl) process.exit(0);
|
|
15
|
+
|
|
16
|
+
// Spawn a new terminal window with the wizard — gives a guaranteed TTY
|
|
17
|
+
// regardless of how npm pipes its own stdout during postinstall.
|
|
18
|
+
const { spawn } = require('child_process');
|
|
19
|
+
const wizardPath = path.resolve(__dirname, 'aicp-tracker.js');
|
|
20
|
+
const nodePath = process.execPath;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
if (process.platform === 'win32') {
|
|
24
|
+
// cmd /k keeps the window open after the wizard finishes so the user can read output
|
|
25
|
+
spawn('cmd.exe', ['/c', 'start', 'cmd', '/k', `"${nodePath}" "${wizardPath}" setup`], { stdio: 'ignore', detached: true }).unref();
|
|
26
|
+
} else if (process.platform === 'darwin') {
|
|
27
|
+
spawn('osascript', ['-e', `tell app "Terminal" to do script "${nodePath} '${wizardPath}' setup"`], { stdio: 'ignore', detached: true }).unref();
|
|
28
|
+
} else {
|
|
29
|
+
// Try common Linux terminal emulators in order
|
|
30
|
+
const terms = ['x-terminal-emulator', 'gnome-terminal', 'xterm', 'konsole'];
|
|
31
|
+
let launched = false;
|
|
32
|
+
for (const term of terms) {
|
|
33
|
+
try {
|
|
34
|
+
spawn(term, ['-e', `${nodePath} "${wizardPath}" setup`], { stdio: 'ignore', detached: true }).unref();
|
|
35
|
+
launched = true;
|
|
36
|
+
break;
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
39
|
+
if (!launched) {
|
|
40
|
+
console.log('\n\x1b[1m AI Code Pulse Tracker installed.\x1b[0m');
|
|
41
|
+
console.log(' Run \x1b[1maicp-tracker setup\x1b[0m to activate tracking.\n');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
console.log('\n\x1b[1m AI Code Pulse Tracker installed.\x1b[0m');
|
|
46
|
+
console.log(' Run \x1b[1maicp-tracker setup\x1b[0m to activate tracking.\n');
|
|
16
47
|
}
|
|
48
|
+
|
|
49
|
+
process.exit(0);
|
|
17
50
|
}
|
|
18
51
|
|
|
52
|
+
// ── When called directly (aicp-tracker setup) ─────────────────────────────────
|
|
53
|
+
|
|
19
54
|
const { prompt } = require('enquirer');
|
|
20
55
|
const { execSync } = require('child_process');
|
|
21
56
|
const fs = require('fs');
|
|
22
57
|
const os = require('os');
|
|
23
|
-
const path = require('path');
|
|
24
58
|
const config = require('../src/config');
|
|
25
59
|
const daemon = require('../src/daemon');
|
|
26
60
|
|
|
@@ -44,14 +78,11 @@ function installAutoStart() {
|
|
|
44
78
|
|
|
45
79
|
try {
|
|
46
80
|
if (process.platform === 'win32') {
|
|
47
|
-
// Windows Task Scheduler: run at every login, current user only
|
|
48
81
|
execSync(
|
|
49
82
|
`schtasks /create /tn "${TASK_NAME}" /tr "\\"${nodePath}\\" \\"${scriptPath}\\" start" /sc ONLOGON /f`,
|
|
50
83
|
{ stdio: 'ignore' }
|
|
51
84
|
);
|
|
52
|
-
|
|
53
85
|
} else if (process.platform === 'darwin') {
|
|
54
|
-
// macOS launchd: load on login
|
|
55
86
|
const plistDir = path.join(os.homedir(), 'Library', 'LaunchAgents');
|
|
56
87
|
const plistPath = path.join(plistDir, 'com.aicp-tracker.plist');
|
|
57
88
|
fs.mkdirSync(plistDir, { recursive: true });
|
|
@@ -71,9 +102,7 @@ function installAutoStart() {
|
|
|
71
102
|
</dict>
|
|
72
103
|
</plist>`);
|
|
73
104
|
execSync(`launchctl load "${plistPath}"`, { stdio: 'ignore' });
|
|
74
|
-
|
|
75
105
|
} else {
|
|
76
|
-
// Linux: systemd user service
|
|
77
106
|
const unitDir = path.join(os.homedir(), '.config', 'systemd', 'user');
|
|
78
107
|
const unitPath = path.join(unitDir, 'aicp-tracker.service');
|
|
79
108
|
fs.mkdirSync(unitDir, { recursive: true });
|
|
@@ -90,7 +119,6 @@ WantedBy=default.target
|
|
|
90
119
|
`);
|
|
91
120
|
execSync('systemctl --user daemon-reload && systemctl --user enable --now aicp-tracker', { stdio: 'ignore' });
|
|
92
121
|
}
|
|
93
|
-
|
|
94
122
|
return true;
|
|
95
123
|
} catch {
|
|
96
124
|
return false;
|
|
@@ -115,12 +143,12 @@ async function register(email) {
|
|
|
115
143
|
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
116
144
|
|
|
117
145
|
async function main() {
|
|
118
|
-
console.log('\n\x1b[1m AI Code Pulse Tracker —
|
|
146
|
+
console.log('\n\x1b[1m AI Code Pulse Tracker — setup\x1b[0m\n');
|
|
119
147
|
|
|
120
148
|
let existing = null;
|
|
121
149
|
try { existing = config.load(); } catch {}
|
|
122
150
|
if (existing?.vcsUrl) {
|
|
123
|
-
console.log(` Already configured (${existing.vcsUrl}).
|
|
151
|
+
console.log(` Already configured (${existing.vcsUrl}). Answers below will overwrite it.\n`);
|
|
124
152
|
}
|
|
125
153
|
|
|
126
154
|
const answers = await prompt([
|
|
@@ -174,6 +202,11 @@ async function main() {
|
|
|
174
202
|
console.log(' \x1b[32m✔\x1b[0m Tracker running. Usage will be sent every 5 minutes.\n');
|
|
175
203
|
}
|
|
176
204
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
205
|
+
module.exports = { main };
|
|
206
|
+
|
|
207
|
+
// Auto-run when invoked directly (aicp-tracker setup) or required without await
|
|
208
|
+
if (require.main === module || process.env.npm_lifecycle_event === 'postinstall') {
|
|
209
|
+
main().catch(e => {
|
|
210
|
+
console.warn('\n [aicp-tracker] Setup error:', e.message, '\n Run `aicp-tracker setup` to try again.\n');
|
|
211
|
+
});
|
|
212
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicp-tracker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "AI Code Pulse — Claude Code usage tracker for JIRA cost attribution",
|
|
5
5
|
"main": "src/daemon.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,6 +15,6 @@
|
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=18"
|
|
17
17
|
},
|
|
18
|
-
"license": "
|
|
18
|
+
"license": "MIT",
|
|
19
19
|
"private": false
|
|
20
20
|
}
|
package/LICENSE
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2026 Alexey Pavlenko
|
|
2
|
-
|
|
3
|
-
All rights reserved.
|
|
4
|
-
|
|
5
|
-
This software is proprietary and confidential.
|
|
6
|
-
|
|
7
|
-
Permission is granted to install and use this software solely for the purpose
|
|
8
|
-
of interacting with the AICP Tracker service, and only with a valid and active subscription.
|
|
9
|
-
|
|
10
|
-
You may NOT:
|
|
11
|
-
- copy, modify, merge, publish, distribute, sublicense, or sell the software
|
|
12
|
-
- use the software in any competing product or service
|
|
13
|
-
- reverse engineer, decompile, or attempt to extract source code or algorithms
|
|
14
|
-
- remove or alter any proprietary notices
|
|
15
|
-
|
|
16
|
-
The software is provided "as is", without warranty of any kind.
|
|
17
|
-
|
|
18
|
-
Access to the source code (if provided) is for review purposes only and does
|
|
19
|
-
not grant any rights beyond what is explicitly stated in this license.
|