@token-dashboard/codex-usage-uploader 0.1.3 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@token-dashboard/codex-usage-uploader",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Codex 用量上报 CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,15 +12,15 @@
12
12
  "README.md"
13
13
  ],
14
14
  "scripts": {
15
- "init": "node bin/codex-usage-uploader.js init --backend-url http://localhost:8086",
16
- "start": "node bin/codex-usage-uploader.js start",
17
- "stop": "node bin/codex-usage-uploader.js stop",
18
- "restart": "node bin/codex-usage-uploader.js restart",
19
- "status": "node bin/codex-usage-uploader.js status",
20
- "usage": "node bin/codex-usage-uploader.js usage",
21
- "logs": "node bin/codex-usage-uploader.js logs",
22
- "clear": "node bin/codex-usage-uploader.js clear",
23
- "uninstall": "node bin/codex-usage-uploader.js uninstall"
15
+ "init": "node ./bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json init --backend-url http://localhost:8086",
16
+ "start": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json start",
17
+ "stop": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json stop",
18
+ "restart": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json restart",
19
+ "status": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json status",
20
+ "usage": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json usage",
21
+ "logs": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json logs",
22
+ "clear": "node ./bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json clear",
23
+ "uninstall": "node bin/codex-usage-uploader.js --config-file $HOME/.codex-usage-uploader-dev/config.json uninstall"
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=22.13.0"
package/src/collector.js CHANGED
@@ -516,7 +516,7 @@ export class CodexUsageUploader {
516
516
  let lastError = null;
517
517
  const collectorBody = this.collectorRequestBody();
518
518
 
519
- const rows = this.stateDb.iterDuePendingBatches();
519
+ const rows = this.stateDb.iterPendingBatches();
520
520
 
521
521
  const uploadOne = async (row) => {
522
522
  const payload = this.sanitizeUploadPayload(JSON.parse(row.payload_json));
@@ -1,4 +1,5 @@
1
1
  import fs from 'node:fs';
2
+ import os from 'node:os';
2
3
  import path from 'node:path';
3
4
  import {
4
5
  CLI_NAME,
@@ -23,11 +24,21 @@ import {
23
24
  } from './constants.js';
24
25
  import { stableStringify } from './utils.js';
25
26
 
27
+ const DEFAULT_INSTALL_ROOT_BASE = path.basename(DEFAULT_INSTALL_ROOT);
28
+
29
+ export function deriveEnvSuffix(installRoot) {
30
+ const base = path.basename(installRoot);
31
+ if (!base.startsWith(`${DEFAULT_INSTALL_ROOT_BASE}-`)) return '';
32
+ const envName = base.slice(DEFAULT_INSTALL_ROOT_BASE.length + 1);
33
+ return envName ? `-${envName}` : '';
34
+ }
35
+
26
36
  export function defaultRuntimeConfig(configFile = DEFAULT_CONFIG_FILE) {
27
37
  const installRoot = path.dirname(configFile);
38
+ const envSuffix = deriveEnvSuffix(installRoot);
28
39
  const appRoot = path.join(installRoot, 'app');
29
40
  const currentAppDir = path.join(appRoot, 'current');
30
- const launchdLabel = DEFAULT_LAUNCHD_LABEL;
41
+ const launchdLabel = `${DEFAULT_LAUNCHD_LABEL}${envSuffix}`;
31
42
  return {
32
43
  configFile,
33
44
  installRoot,
@@ -43,7 +54,7 @@ export function defaultRuntimeConfig(configFile = DEFAULT_CONFIG_FILE) {
43
54
  packageSpec: '',
44
55
  localBinDir: path.join(installRoot, 'bin'),
45
56
  localBinPath: path.join(installRoot, 'bin', CLI_NAME),
46
- homeBinLink: DEFAULT_HOME_BIN_LINK,
57
+ homeBinLink: path.join(os.homedir(), 'bin', `${CLI_NAME}${envSuffix}`),
47
58
  stdoutLogPath: path.join(installRoot, 'logs', path.basename(DEFAULT_STDOUT_LOG_PATH)),
48
59
  stderrLogPath: path.join(installRoot, 'logs', path.basename(DEFAULT_STDERR_LOG_PATH)),
49
60
  launchdLabel,
@@ -69,10 +80,11 @@ export function loadRuntimeConfig(configFile = DEFAULT_CONFIG_FILE) {
69
80
 
70
81
  export function normalizeRuntimeConfig(runtime) {
71
82
  const installRoot = runtime.installRoot || DEFAULT_INSTALL_ROOT;
83
+ const envSuffix = deriveEnvSuffix(installRoot);
72
84
  const appRoot = runtime.appRoot || path.join(installRoot, 'app');
73
85
  const currentAppDir = runtime.currentAppDir || path.join(appRoot, 'current');
74
- const localBinDir = runtime.localBinDir || DEFAULT_LOCAL_BIN_DIR;
75
- const launchdLabel = runtime.launchdLabel || DEFAULT_LAUNCHD_LABEL;
86
+ const localBinDir = runtime.localBinDir || path.join(installRoot, 'bin');
87
+ const launchdLabel = runtime.launchdLabel || `${DEFAULT_LAUNCHD_LABEL}${envSuffix}`;
76
88
  const defaultPlistPath = path.join(installRoot, 'launchd', `${launchdLabel}.plist`);
77
89
  const defaultLaunchAgentPath = path.join(
78
90
  path.dirname(DEFAULT_LAUNCH_AGENT_PATH),
@@ -99,7 +111,7 @@ export function normalizeRuntimeConfig(runtime) {
99
111
  packageSpec: runtime.packageSpec || '',
100
112
  localBinDir,
101
113
  localBinPath: runtime.localBinPath || path.join(localBinDir, CLI_NAME),
102
- homeBinLink: runtime.homeBinLink || DEFAULT_HOME_BIN_LINK,
114
+ homeBinLink: runtime.homeBinLink || path.join(os.homedir(), 'bin', `${CLI_NAME}${envSuffix}`),
103
115
  stdoutLogPath: runtime.stdoutLogPath || path.join(installRoot, 'logs', 'stdout.log'),
104
116
  stderrLogPath: runtime.stderrLogPath || path.join(installRoot, 'logs', 'stderr.log'),
105
117
  launchdLabel,
package/src/state-db.js CHANGED
@@ -207,8 +207,8 @@ export class StateDb {
207
207
  this.db.prepare(`
208
208
  INSERT INTO pending_batches(
209
209
  batch_key, status, payload_json, payload_bytes, session_count, turn_count, event_count,
210
- attempt_count, next_retry_at, created_at, updated_at
211
- ) VALUES (?, 'buffering', ?, ?, ?, ?, ?, 0, NULL, ?, ?)
210
+ attempt_count, created_at, updated_at
211
+ ) VALUES (?, 'buffering', ?, ?, ?, ?, ?, 0, ?, ?)
212
212
  `).run(randomBatchKey(), payloadJson, payloadBytes, sessionCount, turnCount, eventCount, ts, ts);
213
213
  }
214
214
  return this.getBufferingBatch();
@@ -224,12 +224,12 @@ export class StateDb {
224
224
  const ts = nowTs();
225
225
  const updateStmt = this.db.prepare(`
226
226
  UPDATE pending_batches
227
- SET status = 'pending', next_retry_at = ?, updated_at = ?
227
+ SET status = 'pending', updated_at = ?
228
228
  WHERE id = ?
229
229
  `);
230
230
  for (const row of rows) {
231
231
  if (force || ts - Number(row.created_at) >= MAX_BUFFER_AGE_SECONDS) {
232
- updateStmt.run(ts, ts, row.id);
232
+ updateStmt.run(ts, row.id);
233
233
  sealed += 1;
234
234
  }
235
235
  }
@@ -247,29 +247,21 @@ export class StateDb {
247
247
  const ts = nowTs();
248
248
  this.db.prepare(`
249
249
  UPDATE pending_batches
250
- SET status = 'pending', next_retry_at = ?, updated_at = ?
250
+ SET status = 'pending', updated_at = ?
251
251
  WHERE id = ?
252
- `).run(ts, ts, row.id);
252
+ `).run(ts, row.id);
253
253
  }
254
254
  return shouldSeal;
255
255
  }
256
256
 
257
- iterDuePendingBatches() {
257
+ iterPendingBatches() {
258
258
  const stmt = this.db.prepare(`
259
259
  SELECT * FROM pending_batches
260
- WHERE status = 'pending' AND (next_retry_at IS NULL OR next_retry_at <= ?)
260
+ WHERE status = 'pending'
261
261
  ORDER BY created_at ASC, id ASC
262
262
  `);
263
263
  stmt.setReadBigInts(true);
264
- return stmt.all(nowTs());
265
- }
266
-
267
- markAllPendingDue() {
268
- this.db.prepare(`
269
- UPDATE pending_batches
270
- SET next_retry_at = 0, updated_at = ?
271
- WHERE status = 'pending'
272
- `).run(nowTs());
264
+ return stmt.all();
273
265
  }
274
266
 
275
267
  markBatchUploaded(batchId) {
@@ -277,12 +269,11 @@ export class StateDb {
277
269
  }
278
270
 
279
271
  markBatchFailed(batchId, attemptCount, errorMessage) {
280
- const nextRetryAt = nowTs() + Math.min(300, 2 ** Math.min(attemptCount, 8));
281
272
  this.db.prepare(`
282
273
  UPDATE pending_batches
283
- SET attempt_count = ?, next_retry_at = ?, last_error = ?, updated_at = ?
274
+ SET attempt_count = ?, last_error = ?, updated_at = ?
284
275
  WHERE id = ?
285
- `).run(attemptCount, nextRetryAt, String(errorMessage).slice(0, 1000), nowTs(), batchId);
276
+ `).run(attemptCount, String(errorMessage).slice(0, 1000), nowTs(), batchId);
286
277
  }
287
278
 
288
279
  resetBackfillState() {