@poco-ai/tokenarena 0.2.1 → 0.2.3
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/dist/chunk-XJKRJ3K2.js +413 -0
- package/dist/chunk-XJKRJ3K2.js.map +1 -0
- package/dist/index.js +754 -221
- package/dist/index.js.map +1 -1
- package/dist/service-4U7K4DKW.js +8 -0
- package/dist/service-4U7K4DKW.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/service.ts
|
|
4
|
+
import { execFileSync } from "child_process";
|
|
5
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
|
6
|
+
import { homedir, platform } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
|
|
9
|
+
// src/infrastructure/ui/format.ts
|
|
10
|
+
var hasColor = Boolean(process.stdout.isTTY && process.env.NO_COLOR !== "1");
|
|
11
|
+
function withCode(code, value) {
|
|
12
|
+
if (!hasColor) return value;
|
|
13
|
+
return `\x1B[${code}m${value}\x1B[0m`;
|
|
14
|
+
}
|
|
15
|
+
function bold(value) {
|
|
16
|
+
return withCode("1", value);
|
|
17
|
+
}
|
|
18
|
+
function dim(value) {
|
|
19
|
+
return withCode("2", value);
|
|
20
|
+
}
|
|
21
|
+
function cyan(value) {
|
|
22
|
+
return withCode("36", value);
|
|
23
|
+
}
|
|
24
|
+
function green(value) {
|
|
25
|
+
return withCode("32", value);
|
|
26
|
+
}
|
|
27
|
+
function yellow(value) {
|
|
28
|
+
return withCode("33", value);
|
|
29
|
+
}
|
|
30
|
+
function red(value) {
|
|
31
|
+
return withCode("31", value);
|
|
32
|
+
}
|
|
33
|
+
function magenta(value) {
|
|
34
|
+
return withCode("35", value);
|
|
35
|
+
}
|
|
36
|
+
function formatHeader(title, subtitle) {
|
|
37
|
+
const lines = [`${cyan("\u25C8")} ${bold(title)}`];
|
|
38
|
+
if (subtitle) {
|
|
39
|
+
lines.push(dim(subtitle));
|
|
40
|
+
}
|
|
41
|
+
return `
|
|
42
|
+
${lines.join("\n")}`;
|
|
43
|
+
}
|
|
44
|
+
function formatSection(title) {
|
|
45
|
+
return `
|
|
46
|
+
${bold(title)}`;
|
|
47
|
+
}
|
|
48
|
+
function formatKeyValue(label, value) {
|
|
49
|
+
return ` ${dim(label.padEnd(14, " "))} ${value}`;
|
|
50
|
+
}
|
|
51
|
+
function formatBullet(value, tone = "neutral") {
|
|
52
|
+
const icon = tone === "success" ? green("\u2714") : tone === "warning" ? yellow("!") : tone === "danger" ? red("\u2716") : cyan("\u2022");
|
|
53
|
+
return ` ${icon} ${value}`;
|
|
54
|
+
}
|
|
55
|
+
function formatMutedPath(path) {
|
|
56
|
+
return dim(path);
|
|
57
|
+
}
|
|
58
|
+
function maskSecret(value, visible = 8) {
|
|
59
|
+
if (!value) return "(empty)";
|
|
60
|
+
if (value.length <= visible) return value;
|
|
61
|
+
return `${value.slice(0, visible)}\u2026`;
|
|
62
|
+
}
|
|
63
|
+
function formatStatusBadge(label, tone = "neutral") {
|
|
64
|
+
if (tone === "success") return green(label);
|
|
65
|
+
if (tone === "warning") return yellow(label);
|
|
66
|
+
if (tone === "danger") return red(label);
|
|
67
|
+
return magenta(label);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/infrastructure/ui/prompts.ts
|
|
71
|
+
import {
|
|
72
|
+
confirm,
|
|
73
|
+
input,
|
|
74
|
+
password,
|
|
75
|
+
select
|
|
76
|
+
} from "@inquirer/prompts";
|
|
77
|
+
function isInteractiveTerminal() {
|
|
78
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
79
|
+
}
|
|
80
|
+
async function promptConfirm(options) {
|
|
81
|
+
return confirm({
|
|
82
|
+
message: options.message,
|
|
83
|
+
default: options.defaultValue
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async function promptText(options) {
|
|
87
|
+
return input({
|
|
88
|
+
message: options.message,
|
|
89
|
+
default: options.defaultValue,
|
|
90
|
+
validate: options.validate
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function promptPassword(options) {
|
|
94
|
+
return password({
|
|
95
|
+
message: options.message,
|
|
96
|
+
mask: options.mask ?? "*",
|
|
97
|
+
validate: options.validate
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async function promptSelect(options) {
|
|
101
|
+
return select({
|
|
102
|
+
message: options.message,
|
|
103
|
+
choices: [...options.choices],
|
|
104
|
+
pageSize: Math.min(Math.max(options.choices.length, 6), 10)
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/utils/command.ts
|
|
109
|
+
import { execSync } from "child_process";
|
|
110
|
+
function isCommandAvailable(command) {
|
|
111
|
+
try {
|
|
112
|
+
execSync(`command -v ${command}`, { stdio: "ignore" });
|
|
113
|
+
return true;
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/utils/logger.ts
|
|
120
|
+
var LOG_LEVELS = {
|
|
121
|
+
debug: 0,
|
|
122
|
+
info: 1,
|
|
123
|
+
warn: 2,
|
|
124
|
+
error: 3
|
|
125
|
+
};
|
|
126
|
+
var Logger = class {
|
|
127
|
+
level;
|
|
128
|
+
constructor(level = "info") {
|
|
129
|
+
this.level = level;
|
|
130
|
+
}
|
|
131
|
+
setLevel(level) {
|
|
132
|
+
this.level = level;
|
|
133
|
+
}
|
|
134
|
+
debug(msg) {
|
|
135
|
+
if (LOG_LEVELS[this.level] <= LOG_LEVELS.debug) {
|
|
136
|
+
process.stderr.write(`[debug] ${msg}
|
|
137
|
+
`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
info(msg) {
|
|
141
|
+
if (LOG_LEVELS[this.level] <= LOG_LEVELS.info) {
|
|
142
|
+
process.stdout.write(`${msg}
|
|
143
|
+
`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
warn(msg) {
|
|
147
|
+
if (LOG_LEVELS[this.level] <= LOG_LEVELS.warn) {
|
|
148
|
+
process.stderr.write(`warn: ${msg}
|
|
149
|
+
`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
error(msg) {
|
|
153
|
+
if (LOG_LEVELS[this.level] <= LOG_LEVELS.error) {
|
|
154
|
+
process.stderr.write(`error: ${msg}
|
|
155
|
+
`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
log(msg) {
|
|
159
|
+
this.info(msg);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
var logger = new Logger();
|
|
163
|
+
|
|
164
|
+
// src/commands/service.ts
|
|
165
|
+
function isLinux() {
|
|
166
|
+
return platform() === "linux";
|
|
167
|
+
}
|
|
168
|
+
function hasSystemctl() {
|
|
169
|
+
return isCommandAvailable("systemctl");
|
|
170
|
+
}
|
|
171
|
+
function getServiceDir() {
|
|
172
|
+
return join(homedir(), ".config/systemd/user");
|
|
173
|
+
}
|
|
174
|
+
function getServiceFile() {
|
|
175
|
+
return join(getServiceDir(), "tokenarena.service");
|
|
176
|
+
}
|
|
177
|
+
function generateServiceContent() {
|
|
178
|
+
const execPath = process.execPath;
|
|
179
|
+
const scriptPath = process.argv[1];
|
|
180
|
+
const path = process.env.PATH || "/usr/local/bin:/usr/bin:/bin";
|
|
181
|
+
const isDev = process.env.TOKEN_ARENA_DEV === "1";
|
|
182
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
183
|
+
let envVars = `Environment="PATH=${path}"`;
|
|
184
|
+
if (isDev) {
|
|
185
|
+
envVars += `
|
|
186
|
+
Environment="TOKEN_ARENA_DEV=1"`;
|
|
187
|
+
}
|
|
188
|
+
if (xdgConfigHome) {
|
|
189
|
+
envVars += `
|
|
190
|
+
Environment="XDG_CONFIG_HOME=${xdgConfigHome}"`;
|
|
191
|
+
}
|
|
192
|
+
return `[Unit]
|
|
193
|
+
Description=TokenArena Daemon - AI Usage Tracker
|
|
194
|
+
After=network-online.target
|
|
195
|
+
Wants=network-online.target
|
|
196
|
+
|
|
197
|
+
[Service]
|
|
198
|
+
Type=simple
|
|
199
|
+
ExecStart="${execPath}" "${scriptPath}" daemon
|
|
200
|
+
Restart=always
|
|
201
|
+
RestartSec=10
|
|
202
|
+
${envVars}
|
|
203
|
+
|
|
204
|
+
[Install]
|
|
205
|
+
WantedBy=default.target
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
function execSystemctl(args) {
|
|
209
|
+
execFileSync("systemctl", ["--user", ...args], {
|
|
210
|
+
stdio: "inherit"
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async function setupService(skipPrompt = false) {
|
|
214
|
+
const serviceDir = getServiceDir();
|
|
215
|
+
const serviceFile = getServiceFile();
|
|
216
|
+
logger.info(formatHeader("\u8BBE\u7F6E systemd \u670D\u52A1", "TokenArena daemon"));
|
|
217
|
+
if (!skipPrompt) {
|
|
218
|
+
const shouldSetup = await promptConfirm({
|
|
219
|
+
message: "\u662F\u5426\u521B\u5EFA\u5E76\u542F\u7528 systemd \u7528\u6237\u670D\u52A1\uFF1F",
|
|
220
|
+
defaultValue: true
|
|
221
|
+
});
|
|
222
|
+
if (!shouldSetup) {
|
|
223
|
+
logger.info(formatBullet("\u5DF2\u53D6\u6D88\u670D\u52A1\u8BBE\u7F6E\u3002"));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
mkdirSync(serviceDir, { recursive: true });
|
|
229
|
+
writeFileSync(serviceFile, generateServiceContent(), "utf-8");
|
|
230
|
+
execSystemctl(["daemon-reload"]);
|
|
231
|
+
execSystemctl(["enable", "tokenarena"]);
|
|
232
|
+
execSystemctl(["start", "tokenarena"]);
|
|
233
|
+
logger.info(formatSection("\u670D\u52A1\u5DF2\u8BBE\u7F6E"));
|
|
234
|
+
logger.info(formatBullet(`\u670D\u52A1\u6587\u4EF6: ${serviceFile}`, "success"));
|
|
235
|
+
logger.info(formatBullet("\u670D\u52A1\u5DF2\u542F\u7528\u5E76\u542F\u52A8", "success"));
|
|
236
|
+
logger.info(
|
|
237
|
+
formatKeyValue("\u67E5\u770B\u72B6\u6001", "systemctl --user status tokenarena")
|
|
238
|
+
);
|
|
239
|
+
} catch (err) {
|
|
240
|
+
logger.error(`\u8BBE\u7F6E\u670D\u52A1\u5931\u8D25: ${err.message}`);
|
|
241
|
+
throw err;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async function startService() {
|
|
245
|
+
const serviceFile = getServiceFile();
|
|
246
|
+
if (!existsSync(serviceFile)) {
|
|
247
|
+
logger.info(
|
|
248
|
+
formatBullet(
|
|
249
|
+
"\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u8FD0\u884C 'tokenarena service setup'\u3002",
|
|
250
|
+
"warning"
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
execSystemctl(["start", "tokenarena"]);
|
|
257
|
+
logger.info(formatBullet("\u670D\u52A1\u5DF2\u542F\u52A8", "success"));
|
|
258
|
+
} catch (err) {
|
|
259
|
+
logger.error(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${err.message}`);
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async function stopService() {
|
|
264
|
+
const serviceFile = getServiceFile();
|
|
265
|
+
if (!existsSync(serviceFile)) {
|
|
266
|
+
logger.info(
|
|
267
|
+
formatBullet(
|
|
268
|
+
"\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u8FD0\u884C 'tokenarena service setup'\u3002",
|
|
269
|
+
"warning"
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
execSystemctl(["stop", "tokenarena"]);
|
|
276
|
+
logger.info(formatBullet("\u670D\u52A1\u5DF2\u505C\u6B62", "success"));
|
|
277
|
+
} catch (err) {
|
|
278
|
+
logger.error(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${err.message}`);
|
|
279
|
+
throw err;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async function restartService() {
|
|
283
|
+
const serviceFile = getServiceFile();
|
|
284
|
+
if (!existsSync(serviceFile)) {
|
|
285
|
+
logger.info(
|
|
286
|
+
formatBullet(
|
|
287
|
+
"\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u8FD0\u884C 'tokenarena service setup'\u3002",
|
|
288
|
+
"warning"
|
|
289
|
+
)
|
|
290
|
+
);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
execSystemctl(["restart", "tokenarena"]);
|
|
295
|
+
logger.info(formatBullet("\u670D\u52A1\u5DF2\u91CD\u542F", "success"));
|
|
296
|
+
} catch (err) {
|
|
297
|
+
logger.error(`\u91CD\u542F\u670D\u52A1\u5931\u8D25: ${err.message}`);
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async function statusService() {
|
|
302
|
+
const serviceFile = getServiceFile();
|
|
303
|
+
if (!existsSync(serviceFile)) {
|
|
304
|
+
logger.info(
|
|
305
|
+
formatBullet(
|
|
306
|
+
"\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u8FD0\u884C 'tokenarena service setup'\u3002",
|
|
307
|
+
"warning"
|
|
308
|
+
)
|
|
309
|
+
);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
execSystemctl(["status", "tokenarena"]);
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async function uninstallService() {
|
|
318
|
+
const serviceFile = getServiceFile();
|
|
319
|
+
if (!existsSync(serviceFile)) {
|
|
320
|
+
logger.info(formatBullet("\u670D\u52A1\u6587\u4EF6\u4E0D\u5B58\u5728\u3002", "warning"));
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const shouldUninstall = await promptConfirm({
|
|
324
|
+
message: "\u662F\u5426\u5378\u8F7D systemd \u670D\u52A1\uFF1F",
|
|
325
|
+
defaultValue: false
|
|
326
|
+
});
|
|
327
|
+
if (!shouldUninstall) {
|
|
328
|
+
logger.info(formatBullet("\u5DF2\u53D6\u6D88\u5378\u8F7D\u3002"));
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
execSystemctl(["stop", "tokenarena"]);
|
|
333
|
+
execSystemctl(["disable", "tokenarena"]);
|
|
334
|
+
rmSync(serviceFile);
|
|
335
|
+
execSystemctl(["daemon-reload"]);
|
|
336
|
+
logger.info(formatSection("\u670D\u52A1\u5DF2\u5378\u8F7D"));
|
|
337
|
+
logger.info(formatBullet("\u670D\u52A1\u5DF2\u505C\u7528\u5E76\u5220\u9664", "success"));
|
|
338
|
+
} catch (err) {
|
|
339
|
+
logger.error(`\u5378\u8F7D\u670D\u52A1\u5931\u8D25: ${err.message}`);
|
|
340
|
+
throw err;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function printUsage() {
|
|
344
|
+
logger.info(formatHeader("TokenArena systemd \u670D\u52A1\u7BA1\u7406"));
|
|
345
|
+
logger.info(formatSection("\u53EF\u7528\u64CD\u4F5C"));
|
|
346
|
+
logger.info(formatBullet("setup - \u521B\u5EFA\u5E76\u542F\u7528\u670D\u52A1"));
|
|
347
|
+
logger.info(formatBullet("start - \u542F\u52A8\u670D\u52A1"));
|
|
348
|
+
logger.info(formatBullet("stop - \u505C\u6B62\u670D\u52A1"));
|
|
349
|
+
logger.info(formatBullet("restart - \u91CD\u542F\u670D\u52A1"));
|
|
350
|
+
logger.info(formatBullet("status - \u67E5\u770B\u670D\u52A1\u72B6\u6001"));
|
|
351
|
+
logger.info(formatBullet("uninstall - \u5378\u8F7D\u670D\u52A1"));
|
|
352
|
+
}
|
|
353
|
+
async function runInstallService(opts) {
|
|
354
|
+
if (!isLinux()) {
|
|
355
|
+
logger.info(
|
|
356
|
+
formatBullet("systemd \u4E0D\u53EF\u7528\u3002\u6B64\u529F\u80FD\u4EC5\u5728 Linux \u7CFB\u7EDF\u4E0A\u652F\u6301\u3002", "warning")
|
|
357
|
+
);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (!hasSystemctl()) {
|
|
361
|
+
logger.info(
|
|
362
|
+
formatBullet("systemd \u4E0D\u53EF\u7528\u3002\u672A\u68C0\u6D4B\u5230 systemctl\u3002", "warning")
|
|
363
|
+
);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const action = opts.action?.toLowerCase();
|
|
367
|
+
if (!action) {
|
|
368
|
+
printUsage();
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
switch (action) {
|
|
372
|
+
case "setup":
|
|
373
|
+
await setupService(opts.skipPrompt);
|
|
374
|
+
break;
|
|
375
|
+
case "start":
|
|
376
|
+
await startService();
|
|
377
|
+
break;
|
|
378
|
+
case "stop":
|
|
379
|
+
await stopService();
|
|
380
|
+
break;
|
|
381
|
+
case "restart":
|
|
382
|
+
await restartService();
|
|
383
|
+
break;
|
|
384
|
+
case "status":
|
|
385
|
+
await statusService();
|
|
386
|
+
break;
|
|
387
|
+
case "uninstall":
|
|
388
|
+
await uninstallService();
|
|
389
|
+
break;
|
|
390
|
+
default:
|
|
391
|
+
logger.error(`\u672A\u77E5\u64CD\u4F5C: ${action}`);
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export {
|
|
397
|
+
formatHeader,
|
|
398
|
+
formatSection,
|
|
399
|
+
formatKeyValue,
|
|
400
|
+
formatBullet,
|
|
401
|
+
formatMutedPath,
|
|
402
|
+
maskSecret,
|
|
403
|
+
formatStatusBadge,
|
|
404
|
+
isInteractiveTerminal,
|
|
405
|
+
promptConfirm,
|
|
406
|
+
promptText,
|
|
407
|
+
promptPassword,
|
|
408
|
+
promptSelect,
|
|
409
|
+
logger,
|
|
410
|
+
isCommandAvailable,
|
|
411
|
+
runInstallService
|
|
412
|
+
};
|
|
413
|
+
//# sourceMappingURL=chunk-XJKRJ3K2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/service.ts","../src/infrastructure/ui/format.ts","../src/infrastructure/ui/prompts.ts","../src/utils/command.ts","../src/utils/logger.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm } from \"../infrastructure/ui/prompts\";\nimport { isCommandAvailable } from \"../utils/command\";\nimport { logger } from \"../utils/logger\";\n\nexport interface InstallServiceOptions {\n action?: string;\n skipPrompt?: boolean;\n}\n\nfunction isLinux(): boolean {\n return platform() === \"linux\";\n}\n\nfunction hasSystemctl(): boolean {\n return isCommandAvailable(\"systemctl\");\n}\n\nfunction getServiceDir(): string {\n return join(homedir(), \".config/systemd/user\");\n}\n\nfunction getServiceFile(): string {\n return join(getServiceDir(), \"tokenarena.service\");\n}\n\nfunction generateServiceContent(): string {\n const execPath = process.execPath;\n const scriptPath = process.argv[1];\n const path = process.env.PATH || \"/usr/local/bin:/usr/bin:/bin\";\n const isDev = process.env.TOKEN_ARENA_DEV === \"1\";\n const xdgConfigHome = process.env.XDG_CONFIG_HOME;\n\n let envVars = `Environment=\"PATH=${path}\"`;\n if (isDev) {\n envVars += `\\nEnvironment=\"TOKEN_ARENA_DEV=1\"`;\n }\n if (xdgConfigHome) {\n envVars += `\\nEnvironment=\"XDG_CONFIG_HOME=${xdgConfigHome}\"`;\n }\n\n return `[Unit]\nDescription=TokenArena Daemon - AI Usage Tracker\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=\"${execPath}\" \"${scriptPath}\" daemon\nRestart=always\nRestartSec=10\n${envVars}\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nfunction execSystemctl(args: string[]): void {\n execFileSync(\"systemctl\", [\"--user\", ...args], {\n stdio: \"inherit\",\n });\n}\n\nasync function setupService(skipPrompt = false): Promise<void> {\n const serviceDir = getServiceDir();\n const serviceFile = getServiceFile();\n\n logger.info(formatHeader(\"设置 systemd 服务\", \"TokenArena daemon\"));\n\n if (!skipPrompt) {\n const shouldSetup = await promptConfirm({\n message: \"是否创建并启用 systemd 用户服务?\",\n defaultValue: true,\n });\n\n if (!shouldSetup) {\n logger.info(formatBullet(\"已取消服务设置。\"));\n return;\n }\n }\n\n try {\n mkdirSync(serviceDir, { recursive: true });\n writeFileSync(serviceFile, generateServiceContent(), \"utf-8\");\n\n execSystemctl([\"daemon-reload\"]);\n execSystemctl([\"enable\", \"tokenarena\"]);\n execSystemctl([\"start\", \"tokenarena\"]);\n\n logger.info(formatSection(\"服务已设置\"));\n logger.info(formatBullet(`服务文件: ${serviceFile}`, \"success\"));\n logger.info(formatBullet(\"服务已启用并启动\", \"success\"));\n logger.info(\n formatKeyValue(\"查看状态\", \"systemctl --user status tokenarena\"),\n );\n } catch (err) {\n logger.error(`设置服务失败: ${(err as Error).message}`);\n throw err;\n }\n}\n\nasync function startService(): Promise<void> {\n const serviceFile = getServiceFile();\n\n if (!existsSync(serviceFile)) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"start\", \"tokenarena\"]);\n logger.info(formatBullet(\"服务已启动\", \"success\"));\n } catch (err) {\n logger.error(`启动服务失败: ${(err as Error).message}`);\n throw err;\n }\n}\n\nasync function stopService(): Promise<void> {\n const serviceFile = getServiceFile();\n\n if (!existsSync(serviceFile)) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"stop\", \"tokenarena\"]);\n logger.info(formatBullet(\"服务已停止\", \"success\"));\n } catch (err) {\n logger.error(`停止服务失败: ${(err as Error).message}`);\n throw err;\n }\n}\n\nasync function restartService(): Promise<void> {\n const serviceFile = getServiceFile();\n\n if (!existsSync(serviceFile)) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"restart\", \"tokenarena\"]);\n logger.info(formatBullet(\"服务已重启\", \"success\"));\n } catch (err) {\n logger.error(`重启服务失败: ${(err as Error).message}`);\n throw err;\n }\n}\n\nasync function statusService(): Promise<void> {\n const serviceFile = getServiceFile();\n\n if (!existsSync(serviceFile)) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"status\", \"tokenarena\"]);\n } catch {\n // systemctl status exits non-zero for inactive/failed services.\n // Output is already shown via stdio inherit, no need to print error.\n }\n}\n\nasync function uninstallService(): Promise<void> {\n const serviceFile = getServiceFile();\n\n if (!existsSync(serviceFile)) {\n logger.info(formatBullet(\"服务文件不存在。\", \"warning\"));\n return;\n }\n\n const shouldUninstall = await promptConfirm({\n message: \"是否卸载 systemd 服务?\",\n defaultValue: false,\n });\n\n if (!shouldUninstall) {\n logger.info(formatBullet(\"已取消卸载。\"));\n return;\n }\n\n try {\n execSystemctl([\"stop\", \"tokenarena\"]);\n execSystemctl([\"disable\", \"tokenarena\"]);\n rmSync(serviceFile);\n execSystemctl([\"daemon-reload\"]);\n\n logger.info(formatSection(\"服务已卸载\"));\n logger.info(formatBullet(\"服务已停用并删除\", \"success\"));\n } catch (err) {\n logger.error(`卸载服务失败: ${(err as Error).message}`);\n throw err;\n }\n}\n\nfunction printUsage(): void {\n logger.info(formatHeader(\"TokenArena systemd 服务管理\"));\n logger.info(formatSection(\"可用操作\"));\n logger.info(formatBullet(\"setup - 创建并启用服务\"));\n logger.info(formatBullet(\"start - 启动服务\"));\n logger.info(formatBullet(\"stop - 停止服务\"));\n logger.info(formatBullet(\"restart - 重启服务\"));\n logger.info(formatBullet(\"status - 查看服务状态\"));\n logger.info(formatBullet(\"uninstall - 卸载服务\"));\n}\n\nexport async function runInstallService(\n opts: InstallServiceOptions,\n): Promise<void> {\n if (!isLinux()) {\n logger.info(\n formatBullet(\"systemd 不可用。此功能仅在 Linux 系统上支持。\", \"warning\"),\n );\n return;\n }\n\n if (!hasSystemctl()) {\n logger.info(\n formatBullet(\"systemd 不可用。未检测到 systemctl。\", \"warning\"),\n );\n return;\n }\n\n const action = opts.action?.toLowerCase();\n\n if (!action) {\n printUsage();\n return;\n }\n\n switch (action) {\n case \"setup\":\n await setupService(opts.skipPrompt);\n break;\n case \"start\":\n await startService();\n break;\n case \"stop\":\n await stopService();\n break;\n case \"restart\":\n await restartService();\n break;\n case \"status\":\n await statusService();\n break;\n case \"uninstall\":\n await uninstallService();\n break;\n default:\n logger.error(`未知操作: ${action}`);\n process.exit(1);\n }\n}\n","const hasColor = Boolean(process.stdout.isTTY && process.env.NO_COLOR !== \"1\");\n\nfunction withCode(code: string, value: string): string {\n if (!hasColor) return value;\n return `\\u001b[${code}m${value}\\u001b[0m`;\n}\n\nexport function bold(value: string): string {\n return withCode(\"1\", value);\n}\n\nexport function dim(value: string): string {\n return withCode(\"2\", value);\n}\n\nexport function cyan(value: string): string {\n return withCode(\"36\", value);\n}\n\nexport function green(value: string): string {\n return withCode(\"32\", value);\n}\n\nexport function yellow(value: string): string {\n return withCode(\"33\", value);\n}\n\nexport function red(value: string): string {\n return withCode(\"31\", value);\n}\n\nexport function magenta(value: string): string {\n return withCode(\"35\", value);\n}\n\nexport function formatHeader(title: string, subtitle?: string): string {\n const lines = [`${cyan(\"◈\")} ${bold(title)}`];\n if (subtitle) {\n lines.push(dim(subtitle));\n }\n return `\\n${lines.join(\"\\n\")}`;\n}\n\nexport function formatSection(title: string): string {\n return `\\n${bold(title)}`;\n}\n\nexport function formatKeyValue(label: string, value: string): string {\n return ` ${dim(label.padEnd(14, \" \"))} ${value}`;\n}\n\nexport function formatBullet(\n value: string,\n tone: \"neutral\" | \"success\" | \"warning\" | \"danger\" = \"neutral\",\n): string {\n const icon =\n tone === \"success\"\n ? green(\"✔\")\n : tone === \"warning\"\n ? yellow(\"!\")\n : tone === \"danger\"\n ? red(\"✖\")\n : cyan(\"•\");\n return ` ${icon} ${value}`;\n}\n\nexport function formatMutedPath(path: string): string {\n return dim(path);\n}\n\nexport function maskSecret(value: string, visible = 8): string {\n if (!value) return \"(empty)\";\n if (value.length <= visible) return value;\n return `${value.slice(0, visible)}…`;\n}\n\nexport function formatDurationMinutes(minutes: number): string {\n if (minutes < 60) return `${minutes} 分钟`;\n const hours = Math.floor(minutes / 60);\n const restMinutes = minutes % 60;\n return restMinutes > 0\n ? `${hours} 小时 ${restMinutes} 分钟`\n : `${hours} 小时`;\n}\n\nexport function formatStatusBadge(\n label: string,\n tone: \"success\" | \"warning\" | \"danger\" | \"neutral\" = \"neutral\",\n): string {\n if (tone === \"success\") return green(label);\n if (tone === \"warning\") return yellow(label);\n if (tone === \"danger\") return red(label);\n return magenta(label);\n}\n","import {\n type Choice,\n confirm,\n input,\n password,\n select,\n} from \"@inquirer/prompts\";\n\nexport function isInteractiveTerminal(): boolean {\n return Boolean(process.stdin.isTTY && process.stdout.isTTY);\n}\n\nexport async function promptConfirm(options: {\n message: string;\n defaultValue?: boolean;\n}): Promise<boolean> {\n return confirm({\n message: options.message,\n default: options.defaultValue,\n });\n}\n\nexport async function promptText(options: {\n message: string;\n defaultValue?: string;\n validate?: (value: string) => boolean | string;\n}): Promise<string> {\n return input({\n message: options.message,\n default: options.defaultValue,\n validate: options.validate,\n });\n}\n\nexport async function promptPassword(options: {\n message: string;\n mask?: string;\n validate?: (value: string) => boolean | string;\n}): Promise<string> {\n return password({\n message: options.message,\n mask: options.mask ?? \"*\",\n validate: options.validate,\n });\n}\n\nexport async function promptSelect<T>(options: {\n message: string;\n choices: ReadonlyArray<Choice<T>>;\n}): Promise<T> {\n return select({\n message: options.message,\n choices: [...options.choices],\n pageSize: Math.min(Math.max(options.choices.length, 6), 10),\n });\n}\n","import { execSync } from \"node:child_process\";\n\n/**\n * Check if a command is available in PATH.\n * Uses POSIX-standard `command -v` which is more reliable than `which`.\n *\n * @param command - The command name to check (e.g., 'systemctl', 'git')\n * @returns true if the command exists, false otherwise\n *\n * @remarks\n * Ensure you're using macOS/Linux. This uses shell built-in `command -v`\n * which may not be available on Windows.\n */\nexport function isCommandAvailable(command: string): boolean {\n try {\n execSync(`command -v ${command}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n","type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nexport class Logger {\n private level: LogLevel;\n\n constructor(level: LogLevel = \"info\") {\n this.level = level;\n }\n\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n debug(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.debug) {\n process.stderr.write(`[debug] ${msg}\\n`);\n }\n }\n\n info(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.info) {\n process.stdout.write(`${msg}\\n`);\n }\n }\n\n warn(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.warn) {\n process.stderr.write(`warn: ${msg}\\n`);\n }\n }\n\n error(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.error) {\n process.stderr.write(`error: ${msg}\\n`);\n }\n }\n\n log(msg: string): void {\n this.info(msg);\n }\n}\n\nexport const logger = new Logger();\n"],"mappings":"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","names":[]}
|