@slock-ai/daemon 0.46.1 → 0.46.2-staging.20260509074134
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-XW57NR6Y.js → chunk-FG5JGA67.js} +112 -20
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -6830,6 +6830,7 @@ function acquireDaemonMachineLock(options) {
|
|
|
6830
6830
|
import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, rmSync as rmSync3, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
6831
6831
|
import path13 from "path";
|
|
6832
6832
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
6833
|
+
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
6833
6834
|
var DEFAULT_MAX_FILES = 8;
|
|
6834
6835
|
var DIAGNOSTIC_ID_ATTRS = /* @__PURE__ */ new Set([
|
|
6835
6836
|
"serverId",
|
|
@@ -6846,14 +6847,25 @@ var DIAGNOSTIC_ID_ATTRS = /* @__PURE__ */ new Set([
|
|
|
6846
6847
|
var LocalRotatingTraceSink = class {
|
|
6847
6848
|
traceDir;
|
|
6848
6849
|
maxFileBytes;
|
|
6850
|
+
maxFileAgeMs;
|
|
6849
6851
|
maxFiles;
|
|
6852
|
+
nowMsProvider;
|
|
6850
6853
|
currentFile = null;
|
|
6854
|
+
currentFileOpenedAtMs = null;
|
|
6851
6855
|
currentSize = 0;
|
|
6852
6856
|
sequence = 0;
|
|
6853
6857
|
constructor(options) {
|
|
6854
6858
|
this.traceDir = path13.join(options.machineDir, "traces");
|
|
6855
6859
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
6860
|
+
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
6861
|
+
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
6862
|
+
this.maxFileAgeMs = baseAgeMs + ageJitterMs;
|
|
6856
6863
|
this.maxFiles = Math.max(1, Math.floor(options.maxFiles ?? DEFAULT_MAX_FILES));
|
|
6864
|
+
this.nowMsProvider = options.nowMsProvider ?? Date.now;
|
|
6865
|
+
}
|
|
6866
|
+
/** Exposed for observability — the effective rotation age after jitter. */
|
|
6867
|
+
getMaxFileAgeMs() {
|
|
6868
|
+
return this.maxFileAgeMs;
|
|
6857
6869
|
}
|
|
6858
6870
|
record(span) {
|
|
6859
6871
|
try {
|
|
@@ -6870,13 +6882,16 @@ var LocalRotatingTraceSink = class {
|
|
|
6870
6882
|
}
|
|
6871
6883
|
ensureFile(nextBytes) {
|
|
6872
6884
|
mkdirSync6(this.traceDir, { recursive: true, mode: 448 });
|
|
6873
|
-
|
|
6885
|
+
const nowMs = this.nowMsProvider();
|
|
6886
|
+
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
6887
|
+
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
6874
6888
|
this.currentFile = path13.join(
|
|
6875
6889
|
this.traceDir,
|
|
6876
|
-
`daemon-trace-${safeTimestamp(
|
|
6890
|
+
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
6877
6891
|
);
|
|
6878
6892
|
writeFileSync9(this.currentFile, "", { flag: "a", mode: 384 });
|
|
6879
6893
|
this.currentSize = statSync4(this.currentFile).size;
|
|
6894
|
+
this.currentFileOpenedAtMs = nowMs;
|
|
6880
6895
|
this.pruneOldFiles();
|
|
6881
6896
|
}
|
|
6882
6897
|
}
|
|
@@ -6961,7 +6976,7 @@ function isDiagnosticIdAttr(key) {
|
|
|
6961
6976
|
}
|
|
6962
6977
|
|
|
6963
6978
|
// src/traceBundleUpload.ts
|
|
6964
|
-
import { createHash as
|
|
6979
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
6965
6980
|
import { gzipSync } from "zlib";
|
|
6966
6981
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
6967
6982
|
import path14 from "path";
|
|
@@ -7090,6 +7105,35 @@ async function uploadWithSignedCapability({
|
|
|
7090
7105
|
return { capability, session, uploadResponse };
|
|
7091
7106
|
}
|
|
7092
7107
|
|
|
7108
|
+
// src/traceJitter.ts
|
|
7109
|
+
import { createHash as createHash2 } from "crypto";
|
|
7110
|
+
var INITIAL_UPLOAD_DELAY_SPAN_MS = 3e4;
|
|
7111
|
+
var UPLOAD_INTERVAL_JITTER_SPAN_MS = 6e4;
|
|
7112
|
+
var MAX_FILE_AGE_JITTER_SPAN_MS = 6e4;
|
|
7113
|
+
function computeTraceJitter(lockId) {
|
|
7114
|
+
const seed = createHash2("sha256").update(lockId).digest();
|
|
7115
|
+
return {
|
|
7116
|
+
initialUploadDelayMs: seed.readUInt32BE(0) % INITIAL_UPLOAD_DELAY_SPAN_MS,
|
|
7117
|
+
uploadIntervalJitterMs: seed.readUInt32BE(4) % UPLOAD_INTERVAL_JITTER_SPAN_MS,
|
|
7118
|
+
maxFileAgeJitterMs: seed.readUInt32BE(8) % MAX_FILE_AGE_JITTER_SPAN_MS
|
|
7119
|
+
};
|
|
7120
|
+
}
|
|
7121
|
+
var NO_JITTER = {
|
|
7122
|
+
initialUploadDelayMs: 0,
|
|
7123
|
+
uploadIntervalJitterMs: 0,
|
|
7124
|
+
maxFileAgeJitterMs: 0
|
|
7125
|
+
};
|
|
7126
|
+
function bucketDelayMs(delayMs) {
|
|
7127
|
+
if (delayMs < 1e3) return "0-1s";
|
|
7128
|
+
if (delayMs < 5e3) return "1-5s";
|
|
7129
|
+
if (delayMs < 15e3) return "5-15s";
|
|
7130
|
+
if (delayMs < 3e4) return "15-30s";
|
|
7131
|
+
if (delayMs < 6e4) return "30-60s";
|
|
7132
|
+
if (delayMs < 3e5) return "60s-5m";
|
|
7133
|
+
if (delayMs < 6e5) return "5-10m";
|
|
7134
|
+
return "10m+";
|
|
7135
|
+
}
|
|
7136
|
+
|
|
7093
7137
|
// src/traceBundleUpload.ts
|
|
7094
7138
|
var TRACE_UPLOAD_SCOPE = "daemon-trace-bundle:create";
|
|
7095
7139
|
var DEFAULT_UPLOAD_INTERVAL_MS = 5 * 60 * 1e3;
|
|
@@ -7097,30 +7141,66 @@ var DEFAULT_MIN_FILE_AGE_MS = 60 * 1e3;
|
|
|
7097
7141
|
var DEFAULT_MAX_FILES_PER_RUN = 4;
|
|
7098
7142
|
var DaemonTraceBundleUploader = class {
|
|
7099
7143
|
options;
|
|
7100
|
-
|
|
7144
|
+
jitter;
|
|
7145
|
+
timers;
|
|
7146
|
+
initialDelayTimer = null;
|
|
7147
|
+
intervalTimer = null;
|
|
7148
|
+
stopped = false;
|
|
7101
7149
|
constructor(options) {
|
|
7102
7150
|
this.options = options;
|
|
7151
|
+
this.jitter = options.jitter ?? (options.lockId ? computeTraceJitter(options.lockId) : NO_JITTER);
|
|
7152
|
+
this.timers = options.timers ?? {
|
|
7153
|
+
setTimeout: globalThis.setTimeout.bind(globalThis),
|
|
7154
|
+
setInterval: globalThis.setInterval.bind(globalThis),
|
|
7155
|
+
clearTimeout: globalThis.clearTimeout.bind(globalThis),
|
|
7156
|
+
clearInterval: globalThis.clearInterval.bind(globalThis)
|
|
7157
|
+
};
|
|
7103
7158
|
}
|
|
7104
7159
|
start() {
|
|
7105
|
-
if (this.
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7160
|
+
if (this.stopped) return;
|
|
7161
|
+
if (this.initialDelayTimer || this.intervalTimer) return;
|
|
7162
|
+
const initialDelayMs = this.jitter.initialUploadDelayMs;
|
|
7163
|
+
this.initialDelayTimer = this.timers.setTimeout(() => {
|
|
7164
|
+
this.initialDelayTimer = null;
|
|
7165
|
+
if (this.stopped) return;
|
|
7166
|
+
void this.uploadOnce("initial");
|
|
7167
|
+
this.scheduleNextTick();
|
|
7168
|
+
}, initialDelayMs);
|
|
7110
7169
|
}
|
|
7111
7170
|
stop() {
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7171
|
+
this.stopped = true;
|
|
7172
|
+
if (this.initialDelayTimer) {
|
|
7173
|
+
this.timers.clearTimeout(this.initialDelayTimer);
|
|
7174
|
+
this.initialDelayTimer = null;
|
|
7175
|
+
}
|
|
7176
|
+
if (this.intervalTimer) {
|
|
7177
|
+
this.timers.clearTimeout(this.intervalTimer);
|
|
7178
|
+
this.intervalTimer = null;
|
|
7179
|
+
}
|
|
7115
7180
|
}
|
|
7116
|
-
|
|
7181
|
+
/**
|
|
7182
|
+
* Drive a single upload pass. `trigger` is surfaced as a span attribute so
|
|
7183
|
+
* we can distinguish startup drain vs steady-state ticks in ScopeDB.
|
|
7184
|
+
*/
|
|
7185
|
+
async uploadOnce(trigger = "manual") {
|
|
7117
7186
|
const files = await this.findUploadCandidates();
|
|
7118
7187
|
let uploaded = 0;
|
|
7119
7188
|
for (const file of files.slice(0, this.options.maxFilesPerRun ?? DEFAULT_MAX_FILES_PER_RUN)) {
|
|
7120
|
-
if (await this.uploadFile(file)) uploaded += 1;
|
|
7189
|
+
if (await this.uploadFile(file, trigger)) uploaded += 1;
|
|
7121
7190
|
}
|
|
7122
7191
|
return { attempted: files.length, uploaded };
|
|
7123
7192
|
}
|
|
7193
|
+
scheduleNextTick() {
|
|
7194
|
+
if (this.stopped) return;
|
|
7195
|
+
const baseIntervalMs = this.options.intervalMs ?? readPositiveIntegerEnv2("SLOCK_DAEMON_TRACE_UPLOAD_INTERVAL_MS", DEFAULT_UPLOAD_INTERVAL_MS);
|
|
7196
|
+
const nextMs = baseIntervalMs + this.jitter.uploadIntervalJitterMs;
|
|
7197
|
+
this.intervalTimer = this.timers.setTimeout(() => {
|
|
7198
|
+
this.intervalTimer = null;
|
|
7199
|
+
if (this.stopped) return;
|
|
7200
|
+
void this.uploadOnce("interval");
|
|
7201
|
+
this.scheduleNextTick();
|
|
7202
|
+
}, nextMs);
|
|
7203
|
+
}
|
|
7124
7204
|
async findUploadCandidates() {
|
|
7125
7205
|
const traceDir = path14.join(this.options.machineDir, "traces");
|
|
7126
7206
|
let names;
|
|
@@ -7147,13 +7227,16 @@ var DaemonTraceBundleUploader = class {
|
|
|
7147
7227
|
}
|
|
7148
7228
|
return candidates;
|
|
7149
7229
|
}
|
|
7150
|
-
async uploadFile(file) {
|
|
7230
|
+
async uploadFile(file, trigger) {
|
|
7151
7231
|
const span = this.options.tracer?.startSpan("daemon.bundle.upload", {
|
|
7152
7232
|
surface: "daemon",
|
|
7153
7233
|
kind: "producer",
|
|
7154
7234
|
attrs: {
|
|
7155
7235
|
file_present: true,
|
|
7156
|
-
worker_url_present: Boolean(this.options.workerUrl)
|
|
7236
|
+
worker_url_present: Boolean(this.options.workerUrl),
|
|
7237
|
+
upload_trigger: trigger,
|
|
7238
|
+
initial_delay_ms_bucket: bucketDelayMs(this.jitter.initialUploadDelayMs),
|
|
7239
|
+
interval_jitter_ms_bucket: bucketDelayMs(this.jitter.uploadIntervalJitterMs)
|
|
7157
7240
|
}
|
|
7158
7241
|
});
|
|
7159
7242
|
try {
|
|
@@ -7229,7 +7312,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
7229
7312
|
}
|
|
7230
7313
|
};
|
|
7231
7314
|
function sha256Hex(body) {
|
|
7232
|
-
return
|
|
7315
|
+
return createHash3("sha256").update(body).digest("hex");
|
|
7233
7316
|
}
|
|
7234
7317
|
function readPositiveIntegerEnv2(name, fallback) {
|
|
7235
7318
|
const value = process.env[name];
|
|
@@ -7239,6 +7322,7 @@ function readPositiveIntegerEnv2(name, fallback) {
|
|
|
7239
7322
|
}
|
|
7240
7323
|
|
|
7241
7324
|
// src/core.ts
|
|
7325
|
+
var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
7242
7326
|
var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
|
|
7243
7327
|
function parseDaemonCliArgs(args) {
|
|
7244
7328
|
let serverUrl = "";
|
|
@@ -7459,11 +7543,18 @@ var DaemonCore = class {
|
|
|
7459
7543
|
if (!this.options.localTrace) return false;
|
|
7460
7544
|
return process.env.SLOCK_DAEMON_LOCAL_TRACE !== "0";
|
|
7461
7545
|
}
|
|
7546
|
+
resolveTraceJitter() {
|
|
7547
|
+
const lockId = this.machineLock?.lockId;
|
|
7548
|
+
return lockId ? computeTraceJitter(lockId) : NO_JITTER;
|
|
7549
|
+
}
|
|
7462
7550
|
installLocalTraceSink(machineDir) {
|
|
7463
7551
|
if (!this.shouldEnableLocalTrace()) return;
|
|
7552
|
+
const jitter = this.resolveTraceJitter();
|
|
7464
7553
|
this.localTraceSink = new LocalRotatingTraceSink({
|
|
7465
7554
|
machineDir,
|
|
7466
7555
|
maxFileBytes: this.options.localTraceMaxFileBytes ?? readPositiveIntegerEnv3("SLOCK_DAEMON_TRACE_MAX_FILE_BYTES", 5 * 1024 * 1024),
|
|
7556
|
+
maxFileAgeMs: this.options.localTraceMaxFileAgeMs ?? readPositiveIntegerEnv3("SLOCK_DAEMON_TRACE_MAX_FILE_AGE_MS", 5 * 60 * 1e3),
|
|
7557
|
+
maxFileAgeJitterMs: jitter.maxFileAgeJitterMs,
|
|
7467
7558
|
maxFiles: this.options.localTraceMaxFiles ?? readPositiveIntegerEnv3("SLOCK_DAEMON_TRACE_MAX_FILES", 8)
|
|
7468
7559
|
});
|
|
7469
7560
|
this.tracer = new BasicTracer({
|
|
@@ -7474,15 +7565,16 @@ var DaemonCore = class {
|
|
|
7474
7565
|
installTraceBundleUploader(machineDir) {
|
|
7475
7566
|
if (!this.shouldEnableLocalTrace()) return;
|
|
7476
7567
|
if (this.traceBundleUploader) return;
|
|
7477
|
-
|
|
7478
|
-
|
|
7568
|
+
if (process.env.SLOCK_DAEMON_TRACE_UPLOAD_DISABLED === "1") return;
|
|
7569
|
+
const workerUrl = process.env.SLOCK_DAEMON_TRACE_UPLOAD_URL || DEFAULT_TRACE_UPLOAD_URL;
|
|
7479
7570
|
this.traceBundleUploader = new DaemonTraceBundleUploader({
|
|
7480
7571
|
machineDir,
|
|
7481
7572
|
serverUrl: this.options.serverUrl,
|
|
7482
7573
|
apiKey: this.options.apiKey,
|
|
7483
7574
|
workerUrl,
|
|
7484
7575
|
tracer: this.tracer,
|
|
7485
|
-
currentFileProvider: () => this.localTraceSink?.getCurrentFile() ?? null
|
|
7576
|
+
currentFileProvider: () => this.localTraceSink?.getCurrentFile() ?? null,
|
|
7577
|
+
lockId: this.machineLock?.lockId
|
|
7486
7578
|
});
|
|
7487
7579
|
this.traceBundleUploader.start();
|
|
7488
7580
|
}
|
package/dist/core.js
CHANGED
package/dist/index.js
CHANGED