codetime-cli 0.6.0 → 0.7.1
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/codetime.mjs +212 -46
- package/package.json +1 -1
package/bin/codetime.mjs
CHANGED
|
@@ -19,10 +19,13 @@ __export(fs_exports, {
|
|
|
19
19
|
parseJsonFile: () => parseJsonFile,
|
|
20
20
|
pathExists: () => pathExists,
|
|
21
21
|
readJsonIfExists: () => readJsonIfExists,
|
|
22
|
+
readJsonIfExistsTolerant: () => readJsonIfExistsTolerant,
|
|
22
23
|
readTextIfExists: () => readTextIfExists,
|
|
24
|
+
writeFileAtomic: () => writeFileAtomic,
|
|
23
25
|
writeGeneratedFile: () => writeGeneratedFile
|
|
24
26
|
});
|
|
25
|
-
import {
|
|
27
|
+
import { randomBytes } from "node:crypto";
|
|
28
|
+
import { mkdir, open, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
26
29
|
import path from "node:path";
|
|
27
30
|
async function pathExists(filePath) {
|
|
28
31
|
try {
|
|
@@ -56,6 +59,59 @@ function parseJsonFile(filePath, text) {
|
|
|
56
59
|
throw new Error(`Could not parse JSON file ${filePath}: ${error.message}`);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
62
|
+
async function readJsonIfExistsTolerant(filePath, onCorrupt) {
|
|
63
|
+
const text = await readTextIfExists(filePath);
|
|
64
|
+
if (text === null) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(text);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
onCorrupt?.(error);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function writeFileAtomic(filePath, data, options = {}) {
|
|
75
|
+
const dir = path.dirname(filePath);
|
|
76
|
+
await mkdir(dir, { recursive: true });
|
|
77
|
+
const tmpPath = path.join(
|
|
78
|
+
dir,
|
|
79
|
+
`.${path.basename(filePath)}.${process.pid}.${Date.now()}.${randomBytes(6).toString("hex")}.tmp`
|
|
80
|
+
);
|
|
81
|
+
let handle;
|
|
82
|
+
try {
|
|
83
|
+
handle = await open(tmpPath, "wx", options.mode ?? 438);
|
|
84
|
+
await handle.writeFile(data, "utf8");
|
|
85
|
+
if (options.mode !== void 0) {
|
|
86
|
+
await handle.chmod(options.mode);
|
|
87
|
+
}
|
|
88
|
+
await handle.close();
|
|
89
|
+
handle = void 0;
|
|
90
|
+
await renameWithRetry(tmpPath, filePath);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (handle) {
|
|
93
|
+
await handle.close().catch(() => {
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
await rm(tmpPath, { force: true }).catch(() => {
|
|
97
|
+
});
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function renameWithRetry(from, to, attempts = 5) {
|
|
102
|
+
for (let i = 0; ; i++) {
|
|
103
|
+
try {
|
|
104
|
+
await rename(from, to);
|
|
105
|
+
return;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
const code = error.code;
|
|
108
|
+
if (i >= attempts - 1 || code !== "EPERM" && code !== "EACCES" && code !== "EBUSY") {
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
await new Promise((resolve) => setTimeout(resolve, 10 * (i + 1)));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
59
115
|
async function writeGeneratedFile(filePath, content, { dryRun, force, onWrite }) {
|
|
60
116
|
if (dryRun) {
|
|
61
117
|
onWrite(`Would write ${filePath}`);
|
|
@@ -152,7 +208,7 @@ var init_fs = __esm({
|
|
|
152
208
|
|
|
153
209
|
// src/cli.ts
|
|
154
210
|
import { spawn } from "node:child_process";
|
|
155
|
-
import {
|
|
211
|
+
import { rm as rm2, stat as stat6 } from "node:fs/promises";
|
|
156
212
|
import os3 from "node:os";
|
|
157
213
|
import path13 from "node:path";
|
|
158
214
|
import { fileURLToPath } from "node:url";
|
|
@@ -160,7 +216,7 @@ import { fileURLToPath } from "node:url";
|
|
|
160
216
|
// ../shared/src/index.ts
|
|
161
217
|
import { createHash } from "node:crypto";
|
|
162
218
|
var AGENT_TIME_SCHEMA_VERSION = "2026-04-29";
|
|
163
|
-
var AGENT_ROLLUP_SCHEMA_VERSION =
|
|
219
|
+
var AGENT_ROLLUP_SCHEMA_VERSION = 3;
|
|
164
220
|
var TELEMETRY_EVENT_TYPES = [
|
|
165
221
|
"session.started",
|
|
166
222
|
"session.ended",
|
|
@@ -974,7 +1030,7 @@ import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
|
974
1030
|
import path2 from "node:path";
|
|
975
1031
|
|
|
976
1032
|
// src/lib/constants.ts
|
|
977
|
-
var PACKAGE_VERSION = true ? "0.
|
|
1033
|
+
var PACKAGE_VERSION = true ? "0.7.1" : "0.1.1";
|
|
978
1034
|
var DEFAULT_API_URL = "https://codetime.dev";
|
|
979
1035
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
980
1036
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -1932,16 +1988,29 @@ function claudeUsageFromMessage(message) {
|
|
|
1932
1988
|
const outputTokens = numberField(usage, "output_tokens") || 0;
|
|
1933
1989
|
const cachedInputTokens = cacheCreationInputTokens + cacheReadInputTokens;
|
|
1934
1990
|
const totalInputTokens = inputTokens + cachedInputTokens;
|
|
1991
|
+
const cacheCreationSplit = claudeCacheCreationSplit(usage);
|
|
1935
1992
|
return {
|
|
1936
1993
|
tokensInput: totalInputTokens || void 0,
|
|
1937
1994
|
tokensCachedInput: cachedInputTokens || void 0,
|
|
1938
1995
|
tokensCacheCreationInput: cacheCreationInputTokens || void 0,
|
|
1996
|
+
tokensCacheCreation5mInput: cacheCreationSplit?.fiveMinute,
|
|
1997
|
+
tokensCacheCreation1hInput: cacheCreationSplit?.oneHour,
|
|
1939
1998
|
tokensCacheReadInput: cacheReadInputTokens || void 0,
|
|
1940
1999
|
tokensOutput: outputTokens || void 0,
|
|
1941
2000
|
tokensTotal: totalInputTokens + outputTokens || void 0,
|
|
1942
2001
|
modelCalls: 1
|
|
1943
2002
|
};
|
|
1944
2003
|
}
|
|
2004
|
+
function claudeCacheCreationSplit(usage) {
|
|
2005
|
+
const breakdown = usage.cache_creation;
|
|
2006
|
+
if (!isPlainObject(breakdown)) {
|
|
2007
|
+
return void 0;
|
|
2008
|
+
}
|
|
2009
|
+
return {
|
|
2010
|
+
fiveMinute: numberField(breakdown, "ephemeral_5m_input_tokens") || 0,
|
|
2011
|
+
oneHour: numberField(breakdown, "ephemeral_1h_input_tokens") || 0
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
1945
2014
|
function claudeSubagentMetrics(toolResult, fallbackDurationMs) {
|
|
1946
2015
|
const usage = objectField(toolResult, "usage");
|
|
1947
2016
|
const inputTokens = numberField(usage, "input_tokens") || 0;
|
|
@@ -1950,6 +2019,7 @@ function claudeSubagentMetrics(toolResult, fallbackDurationMs) {
|
|
|
1950
2019
|
const outputTokens = numberField(usage, "output_tokens") || 0;
|
|
1951
2020
|
const cachedInputTokens = cacheCreationInputTokens + cacheReadInputTokens;
|
|
1952
2021
|
const totalInputTokens = inputTokens + cachedInputTokens;
|
|
2022
|
+
const cacheCreationSplit = claudeCacheCreationSplit(usage);
|
|
1953
2023
|
const durationMs = numberField(toolResult, "totalDurationMs") || fallbackDurationMs;
|
|
1954
2024
|
return {
|
|
1955
2025
|
durationMs,
|
|
@@ -1958,6 +2028,8 @@ function claudeSubagentMetrics(toolResult, fallbackDurationMs) {
|
|
|
1958
2028
|
tokensInput: totalInputTokens || void 0,
|
|
1959
2029
|
tokensCachedInput: cachedInputTokens || void 0,
|
|
1960
2030
|
tokensCacheCreationInput: cacheCreationInputTokens || void 0,
|
|
2031
|
+
tokensCacheCreation5mInput: cacheCreationSplit?.fiveMinute,
|
|
2032
|
+
tokensCacheCreation1hInput: cacheCreationSplit?.oneHour,
|
|
1961
2033
|
tokensCacheReadInput: cacheReadInputTokens || void 0,
|
|
1962
2034
|
tokensOutput: outputTokens || void 0,
|
|
1963
2035
|
tokensTotal: numberField(toolResult, "totalTokens") || totalInputTokens + outputTokens || void 0
|
|
@@ -4137,6 +4209,7 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4137
4209
|
const lastEventAt = ordered.at(-1)?.ts || startedAt;
|
|
4138
4210
|
const timeBuckets = /* @__PURE__ */ new Map();
|
|
4139
4211
|
const modelRollups = /* @__PURE__ */ new Map();
|
|
4212
|
+
const modelBuckets = /* @__PURE__ */ new Map();
|
|
4140
4213
|
const toolRollups = /* @__PURE__ */ new Map();
|
|
4141
4214
|
const fileRollups = /* @__PURE__ */ new Map();
|
|
4142
4215
|
const turnRollups = /* @__PURE__ */ new Map();
|
|
@@ -4158,6 +4231,8 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4158
4231
|
const eventInputTokens = Math.max(0, event.metrics?.tokensInput || 0);
|
|
4159
4232
|
const eventCachedInputTokens = Math.max(0, event.metrics?.tokensCachedInput || 0);
|
|
4160
4233
|
const eventCacheCreationInputTokens = Math.max(0, event.metrics?.tokensCacheCreationInput || 0);
|
|
4234
|
+
const eventCacheCreation5mInputTokens = Math.max(0, event.metrics?.tokensCacheCreation5mInput || 0);
|
|
4235
|
+
const eventCacheCreation1hInputTokens = Math.max(0, event.metrics?.tokensCacheCreation1hInput || 0);
|
|
4161
4236
|
const eventCacheReadInputTokens = Math.max(0, event.metrics?.tokensCacheReadInput || 0);
|
|
4162
4237
|
const eventOutputTokens = Math.max(0, event.metrics?.tokensOutput || 0);
|
|
4163
4238
|
const eventReasoningOutputTokens = Math.max(0, event.metrics?.tokensReasoningOutput || 0);
|
|
@@ -4278,6 +4353,8 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4278
4353
|
inputTokens: 0,
|
|
4279
4354
|
cachedInputTokens: 0,
|
|
4280
4355
|
cacheCreationInputTokens: 0,
|
|
4356
|
+
cacheCreation5mInputTokens: 0,
|
|
4357
|
+
cacheCreation1hInputTokens: 0,
|
|
4281
4358
|
cacheReadInputTokens: 0,
|
|
4282
4359
|
outputTokens: 0,
|
|
4283
4360
|
reasoningOutputTokens: 0,
|
|
@@ -4288,12 +4365,40 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4288
4365
|
modelRollup.inputTokens += eventInputTokens;
|
|
4289
4366
|
modelRollup.cachedInputTokens += eventCachedInputTokens;
|
|
4290
4367
|
modelRollup.cacheCreationInputTokens += eventCacheCreationInputTokens;
|
|
4368
|
+
modelRollup.cacheCreation5mInputTokens += eventCacheCreation5mInputTokens;
|
|
4369
|
+
modelRollup.cacheCreation1hInputTokens += eventCacheCreation1hInputTokens;
|
|
4291
4370
|
modelRollup.cacheReadInputTokens += eventCacheReadInputTokens;
|
|
4292
4371
|
modelRollup.outputTokens += eventOutputTokens;
|
|
4293
4372
|
modelRollup.reasoningOutputTokens += eventReasoningOutputTokens;
|
|
4294
4373
|
modelRollup.totalTokens += eventTotalTokens;
|
|
4295
4374
|
modelRollup.estimatedCostUsd += eventCostUsd;
|
|
4296
4375
|
modelRollups.set(modelKey, modelRollup);
|
|
4376
|
+
const modelBucketKey = `${bucketTs}\0${modelKey}`;
|
|
4377
|
+
const modelBucket = modelBuckets.get(modelBucketKey) || {
|
|
4378
|
+
ts: bucketTs,
|
|
4379
|
+
model: modelKey,
|
|
4380
|
+
callCount: 0,
|
|
4381
|
+
inputTokens: 0,
|
|
4382
|
+
cachedInputTokens: 0,
|
|
4383
|
+
cacheCreationInputTokens: 0,
|
|
4384
|
+
cacheCreation5mInputTokens: 0,
|
|
4385
|
+
cacheCreation1hInputTokens: 0,
|
|
4386
|
+
cacheReadInputTokens: 0,
|
|
4387
|
+
outputTokens: 0,
|
|
4388
|
+
reasoningOutputTokens: 0,
|
|
4389
|
+
totalTokens: 0
|
|
4390
|
+
};
|
|
4391
|
+
modelBucket.callCount += 1;
|
|
4392
|
+
modelBucket.inputTokens += eventInputTokens;
|
|
4393
|
+
modelBucket.cachedInputTokens += eventCachedInputTokens;
|
|
4394
|
+
modelBucket.cacheCreationInputTokens += eventCacheCreationInputTokens;
|
|
4395
|
+
modelBucket.cacheCreation5mInputTokens += eventCacheCreation5mInputTokens;
|
|
4396
|
+
modelBucket.cacheCreation1hInputTokens += eventCacheCreation1hInputTokens;
|
|
4397
|
+
modelBucket.cacheReadInputTokens += eventCacheReadInputTokens;
|
|
4398
|
+
modelBucket.outputTokens += eventOutputTokens;
|
|
4399
|
+
modelBucket.reasoningOutputTokens += eventReasoningOutputTokens;
|
|
4400
|
+
modelBucket.totalTokens += eventTotalTokens;
|
|
4401
|
+
modelBuckets.set(modelBucketKey, modelBucket);
|
|
4297
4402
|
}
|
|
4298
4403
|
if (event.type === "tool.started") {
|
|
4299
4404
|
bucket.toolCalls += 1;
|
|
@@ -4361,11 +4466,12 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4361
4466
|
const baseRollup = {
|
|
4362
4467
|
rollupKey,
|
|
4363
4468
|
payloadHash: "",
|
|
4364
|
-
//
|
|
4365
|
-
// convention
|
|
4366
|
-
//
|
|
4367
|
-
//
|
|
4368
|
-
//
|
|
4469
|
+
// v3 schema: v2 (gap-clamped turn durations + billable-output token
|
|
4470
|
+
// convention) plus per-model cache-creation TTL split and modelBuckets. Set on
|
|
4471
|
+
// baseRollup (not after) so it participates in payloadHash: every historical
|
|
4472
|
+
// rollup's hash changes, and a re-backfill (uploaded with replace=true by
|
|
4473
|
+
// default) cleanly refreshes all data onto the new convention. This
|
|
4474
|
+
// full-refresh churn is intentional.
|
|
4369
4475
|
schemaVersion: AGENT_ROLLUP_SCHEMA_VERSION,
|
|
4370
4476
|
source: first.source,
|
|
4371
4477
|
project,
|
|
@@ -4390,6 +4496,8 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4390
4496
|
durationMs: Math.max(0, Date.parse(lastEventAt) - Date.parse(startedAt)),
|
|
4391
4497
|
timeBuckets: [...timeBuckets.values()].sort((a, b) => a.ts.localeCompare(b.ts)),
|
|
4392
4498
|
modelRollups: [...modelRollups.values()].sort((a, b) => b.callCount - a.callCount || a.model.localeCompare(b.model)),
|
|
4499
|
+
// Sorted ts ascending, then model lexicographically (wire contract).
|
|
4500
|
+
modelBuckets: [...modelBuckets.values()].sort((a, b) => a.ts.localeCompare(b.ts) || a.model.localeCompare(b.model)),
|
|
4393
4501
|
toolRollups: [...toolRollups.values()].sort((a, b) => b.callCount - a.callCount || a.tool.localeCompare(b.tool)),
|
|
4394
4502
|
fileRollups: [...fileRollups.values()].sort((a, b) => b.writes - a.writes || b.reads - a.reads || a.displayPath.localeCompare(b.displayPath)),
|
|
4395
4503
|
turnRollups: [...turnRollups.values()].map((rollup) => ({
|
|
@@ -4464,7 +4572,7 @@ async function installEntry(entry, options) {
|
|
|
4464
4572
|
});
|
|
4465
4573
|
}
|
|
4466
4574
|
async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
|
|
4467
|
-
const { mkdir:
|
|
4575
|
+
const { mkdir: mkdir3, writeFile: writeFile2 } = await import("node:fs/promises");
|
|
4468
4576
|
const pathMod = await import("node:path");
|
|
4469
4577
|
if (dryRun) {
|
|
4470
4578
|
onWrite(`Would merge ${filePath}`);
|
|
@@ -4485,8 +4593,8 @@ async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
|
|
|
4485
4593
|
onWrite(`Already installed ${filePath}`);
|
|
4486
4594
|
return;
|
|
4487
4595
|
}
|
|
4488
|
-
await
|
|
4489
|
-
await
|
|
4596
|
+
await mkdir3(pathMod.dirname(filePath), { recursive: true });
|
|
4597
|
+
await writeFile2(filePath, nextText, "utf8");
|
|
4490
4598
|
onWrite(`Installed ${filePath}`);
|
|
4491
4599
|
}
|
|
4492
4600
|
function mergeHookObjects(existing, addition) {
|
|
@@ -4524,7 +4632,7 @@ function hookCommandFromGroup(group) {
|
|
|
4524
4632
|
|
|
4525
4633
|
// src/lib/config.ts
|
|
4526
4634
|
import { randomUUID } from "node:crypto";
|
|
4527
|
-
import { existsSync, mkdirSync, readFileSync, rmSync,
|
|
4635
|
+
import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, unlinkSync, writeSync } from "node:fs";
|
|
4528
4636
|
import { homedir, hostname } from "node:os";
|
|
4529
4637
|
import path11 from "node:path";
|
|
4530
4638
|
function configDir(home = homedir()) {
|
|
@@ -4548,30 +4656,87 @@ function readConfig(home = homedir()) {
|
|
|
4548
4656
|
return {};
|
|
4549
4657
|
}
|
|
4550
4658
|
}
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4659
|
+
var atomicTmpCounter = 0;
|
|
4660
|
+
function writeFileAtomicSync(filePath, data, mode) {
|
|
4661
|
+
const dir = path11.dirname(filePath);
|
|
4662
|
+
mkdirSync(dir, { recursive: true });
|
|
4663
|
+
const tmp = path11.join(dir, `.${path11.basename(filePath)}.${process.pid}.${Date.now()}.${(atomicTmpCounter++).toString(36)}.tmp`);
|
|
4664
|
+
let fd;
|
|
4665
|
+
try {
|
|
4666
|
+
fd = openSync(tmp, "wx", mode);
|
|
4667
|
+
writeSync(fd, data);
|
|
4668
|
+
closeSync(fd);
|
|
4669
|
+
fd = void 0;
|
|
4670
|
+
chmodSync(tmp, mode);
|
|
4671
|
+
renameSyncWithRetry(tmp, filePath);
|
|
4672
|
+
} catch (error) {
|
|
4673
|
+
if (fd !== void 0) {
|
|
4674
|
+
try {
|
|
4675
|
+
closeSync(fd);
|
|
4676
|
+
} catch {
|
|
4677
|
+
}
|
|
4678
|
+
}
|
|
4679
|
+
try {
|
|
4680
|
+
unlinkSync(tmp);
|
|
4681
|
+
} catch {
|
|
4682
|
+
}
|
|
4683
|
+
throw error;
|
|
4555
4684
|
}
|
|
4556
|
-
|
|
4557
|
-
|
|
4685
|
+
}
|
|
4686
|
+
function renameSyncWithRetry(from, to, attempts = 5) {
|
|
4687
|
+
for (let i = 0; ; i++) {
|
|
4688
|
+
try {
|
|
4689
|
+
renameSync(from, to);
|
|
4690
|
+
return;
|
|
4691
|
+
} catch (error) {
|
|
4692
|
+
const code = error.code;
|
|
4693
|
+
if (i >= attempts - 1 || code !== "EPERM" && code !== "EACCES" && code !== "EBUSY") {
|
|
4694
|
+
throw error;
|
|
4695
|
+
}
|
|
4696
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10 * (i + 1));
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
function writeConfig(config, home = homedir()) {
|
|
4701
|
+
writeFileAtomicSync(configPath(home), `${JSON.stringify(config, null, 2)}
|
|
4702
|
+
`, 384);
|
|
4558
4703
|
}
|
|
4559
4704
|
function ensureLocalMachineId(home = homedir()) {
|
|
4560
4705
|
const file = machineIdPath(home);
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
return value;
|
|
4565
|
-
}
|
|
4706
|
+
const existing = readMachineId(file);
|
|
4707
|
+
if (existing) {
|
|
4708
|
+
return existing;
|
|
4566
4709
|
}
|
|
4710
|
+
mkdirSync(configDir(home), { recursive: true });
|
|
4567
4711
|
const id = randomUUID();
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4712
|
+
try {
|
|
4713
|
+
const fd = openSync(file, "wx", 384);
|
|
4714
|
+
try {
|
|
4715
|
+
writeSync(fd, `${id}
|
|
4716
|
+
`);
|
|
4717
|
+
} finally {
|
|
4718
|
+
closeSync(fd);
|
|
4719
|
+
}
|
|
4720
|
+
return id;
|
|
4721
|
+
} catch (error) {
|
|
4722
|
+
if (error.code !== "EEXIST") {
|
|
4723
|
+
throw error;
|
|
4724
|
+
}
|
|
4725
|
+
const peer = readMachineId(file);
|
|
4726
|
+
if (peer) {
|
|
4727
|
+
return peer;
|
|
4728
|
+
}
|
|
4729
|
+
writeFileAtomicSync(file, `${id}
|
|
4730
|
+
`, 384);
|
|
4731
|
+
return id;
|
|
4571
4732
|
}
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4733
|
+
}
|
|
4734
|
+
function readMachineId(file) {
|
|
4735
|
+
if (!existsSync(file)) {
|
|
4736
|
+
return null;
|
|
4737
|
+
}
|
|
4738
|
+
const value = readFileSync(file, "utf8").trim();
|
|
4739
|
+
return value.length > 0 ? value : null;
|
|
4575
4740
|
}
|
|
4576
4741
|
function defaultMachineName() {
|
|
4577
4742
|
return hostname();
|
|
@@ -4581,7 +4746,7 @@ function defaultMachineName() {
|
|
|
4581
4746
|
init_fs();
|
|
4582
4747
|
|
|
4583
4748
|
// src/lib/logger.ts
|
|
4584
|
-
import { appendFile, mkdir as mkdir2, rename, stat as stat5 } from "node:fs/promises";
|
|
4749
|
+
import { appendFile, mkdir as mkdir2, rename as rename2, stat as stat5 } from "node:fs/promises";
|
|
4585
4750
|
import { homedir as homedir2 } from "node:os";
|
|
4586
4751
|
import path12 from "node:path";
|
|
4587
4752
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
@@ -4601,7 +4766,7 @@ async function rotateIfNeeded(file) {
|
|
|
4601
4766
|
try {
|
|
4602
4767
|
const info = await stat5(file);
|
|
4603
4768
|
if (info.size > MAX_BYTES) {
|
|
4604
|
-
await
|
|
4769
|
+
await rename2(file, `${file}.1`).catch(() => {
|
|
4605
4770
|
});
|
|
4606
4771
|
}
|
|
4607
4772
|
} catch {
|
|
@@ -5435,7 +5600,7 @@ async function importBackfillPlan(plan, options, ctx, registry) {
|
|
|
5435
5600
|
}
|
|
5436
5601
|
async function purgeForcedSources(sourceDefs, home, options, ctx) {
|
|
5437
5602
|
try {
|
|
5438
|
-
await
|
|
5603
|
+
await rm2(backfillIncrementalStatePath(home), { force: true });
|
|
5439
5604
|
} catch (error) {
|
|
5440
5605
|
debug(ctx, `Failed to clear backfill watermark: ${error.message}
|
|
5441
5606
|
`);
|
|
@@ -5633,7 +5798,11 @@ function syncLocalTriggerLockPath(home) {
|
|
|
5633
5798
|
}
|
|
5634
5799
|
async function readBackfillIncrementalState(home, ctx) {
|
|
5635
5800
|
const statePath = backfillIncrementalStatePath(home);
|
|
5636
|
-
const state = await
|
|
5801
|
+
const state = await readJsonIfExistsTolerant(
|
|
5802
|
+
statePath,
|
|
5803
|
+
ctx ? (error) => debug(ctx, `backfill-state unreadable at ${statePath}; dropping watermarks and re-importing (${error.message})
|
|
5804
|
+
`) : void 0
|
|
5805
|
+
);
|
|
5637
5806
|
if (state === null) {
|
|
5638
5807
|
return { version: BACKFILL_STATE_SCHEMA_VERSION, sources: {} };
|
|
5639
5808
|
}
|
|
@@ -5669,12 +5838,11 @@ async function updateBackfillIncrementalState(home, state, selectedFilesBySource
|
|
|
5669
5838
|
state.sources[source] = { watermarkTs: latest };
|
|
5670
5839
|
}
|
|
5671
5840
|
const statePath = backfillIncrementalStatePath(home);
|
|
5672
|
-
await
|
|
5673
|
-
|
|
5674
|
-
`, "utf8");
|
|
5841
|
+
await writeFileAtomic(statePath, `${JSON.stringify(state, null, 2)}
|
|
5842
|
+
`);
|
|
5675
5843
|
}
|
|
5676
5844
|
async function readSyncLocalTriggerState(statePath) {
|
|
5677
|
-
const state = await
|
|
5845
|
+
const state = await readJsonIfExistsTolerant(statePath);
|
|
5678
5846
|
if (!isPlainObject(state)) {
|
|
5679
5847
|
return { version: 1 };
|
|
5680
5848
|
}
|
|
@@ -5697,12 +5865,11 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
5697
5865
|
return nextState;
|
|
5698
5866
|
}
|
|
5699
5867
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
5700
|
-
await
|
|
5701
|
-
|
|
5702
|
-
`, "utf8");
|
|
5868
|
+
await writeFileAtomic(statePath, `${JSON.stringify(state, null, 2)}
|
|
5869
|
+
`);
|
|
5703
5870
|
}
|
|
5704
5871
|
async function readSyncLocalLock(lockPath) {
|
|
5705
|
-
const lock = await
|
|
5872
|
+
const lock = await readJsonIfExistsTolerant(lockPath);
|
|
5706
5873
|
if (!isPlainObject(lock)) {
|
|
5707
5874
|
return void 0;
|
|
5708
5875
|
}
|
|
@@ -5712,13 +5879,12 @@ async function readSyncLocalLock(lockPath) {
|
|
|
5712
5879
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
5713
5880
|
}
|
|
5714
5881
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
5715
|
-
await
|
|
5716
|
-
|
|
5717
|
-
`, "utf8");
|
|
5882
|
+
await writeFileAtomic(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
5883
|
+
`);
|
|
5718
5884
|
}
|
|
5719
5885
|
async function clearSyncLocalLock(lockPath) {
|
|
5720
5886
|
try {
|
|
5721
|
-
await
|
|
5887
|
+
await rm2(lockPath, { force: true });
|
|
5722
5888
|
} catch (error) {
|
|
5723
5889
|
if (error.code !== "ENOENT") {
|
|
5724
5890
|
throw error;
|
package/package.json
CHANGED