@hardkas/core 0.5.5-alpha → 0.6.1-alpha

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +402 -14
  2. package/dist/index.js +807 -65
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,244 @@
1
1
  // src/index.ts
2
2
  import { z } from "zod";
3
3
 
4
+ // src/append-coordinator.ts
5
+ import fs from "fs";
6
+ import path2 from "path";
7
+
8
+ // src/telemetry.ts
9
+ import path from "path";
10
+ import crypto2 from "crypto";
11
+ import { AsyncLocalStorage } from "async_hooks";
12
+ var TelemetryManager = class {
13
+ rootDir = null;
14
+ currentContext = {};
15
+ // Track sandboxes that need to be preserved because they hit severe anomalies
16
+ preservedSandboxes = /* @__PURE__ */ new Set();
17
+ constructor(rootDir) {
18
+ if (rootDir) this.rootDir = rootDir;
19
+ }
20
+ init(rootDir) {
21
+ this.rootDir = rootDir;
22
+ }
23
+ setContext(context) {
24
+ this.currentContext = { ...this.currentContext, ...context };
25
+ }
26
+ clearContext() {
27
+ this.currentContext = {};
28
+ }
29
+ getContext() {
30
+ return this.currentContext;
31
+ }
32
+ logAnomaly(anomalyType, severity, subsystem, details, sandboxOverride) {
33
+ const logDir = this.rootDir ? path.join(this.rootDir, ".hardkas", "telemetry") : sandboxOverride ? path.join(sandboxOverride, ".hardkas", "telemetry") : null;
34
+ if (!logDir) return;
35
+ const nowStr = (/* @__PURE__ */ new Date()).toISOString();
36
+ const runId = this.currentContext.seed ? `run-${this.currentContext.seed}` : "run-core";
37
+ const bucket = this.currentContext.bucket || "core";
38
+ let mappedSeverity = "nominal";
39
+ if (severity === "medium") mappedSeverity = "elevated";
40
+ else if (severity === "high" || severity === "critical") mappedSeverity = "critical";
41
+ const canonicalPayloadRaw = JSON.stringify({
42
+ runId,
43
+ bucket,
44
+ type: anomalyType,
45
+ severity: mappedSeverity,
46
+ caseId: this.currentContext.caseId,
47
+ payload: {
48
+ subsystem,
49
+ details,
50
+ sandbox: sandboxOverride
51
+ }
52
+ });
53
+ const eventHash = crypto2.createHash("sha256").update(canonicalPayloadRaw).digest("hex").slice(0, 32);
54
+ const eventIdRaw = `${eventHash}-${nowStr}`;
55
+ const eventId = crypto2.createHash("sha256").update(eventIdRaw).digest("hex").slice(0, 32);
56
+ const event = {
57
+ schemaVersion: "hardkas.telemetry.v1",
58
+ eventId,
59
+ eventHash,
60
+ timestamp: nowStr,
61
+ source: "core-runtime",
62
+ runId,
63
+ bucket,
64
+ type: anomalyType,
65
+ severity: mappedSeverity,
66
+ caseId: this.currentContext.caseId,
67
+ payload: {
68
+ subsystem,
69
+ details,
70
+ sandbox: sandboxOverride
71
+ }
72
+ };
73
+ if (severity === "high" || severity === "critical" || anomalyType === "REPLAY_RECONCILIATION" || anomalyType === "NORMALIZATION_COLLISION") {
74
+ if (sandboxOverride) {
75
+ this.preservedSandboxes.add(sandboxOverride);
76
+ }
77
+ }
78
+ try {
79
+ const logFile = path.join(logDir, "telemetry.jsonl");
80
+ const root = this.rootDir || sandboxOverride || process.cwd();
81
+ AppendCoordinator.appendAtomic(logFile, JSON.stringify(event), root);
82
+ } catch (err) {
83
+ }
84
+ }
85
+ shouldPreserveSandbox(sandboxDir) {
86
+ return this.preservedSandboxes.has(sandboxDir);
87
+ }
88
+ };
89
+ var telemetryContextStorage = new AsyncLocalStorage();
90
+ var globalTelemetry = new TelemetryManager();
91
+ function getTelemetry() {
92
+ return telemetryContextStorage.getStore() || globalTelemetry;
93
+ }
94
+ var TelemetryProxy = class {
95
+ logAnomaly(anomalyType, severity, subsystem, details, sandboxOverride) {
96
+ return getTelemetry().logAnomaly(anomalyType, severity, subsystem, details, sandboxOverride);
97
+ }
98
+ init(rootDir) {
99
+ return getTelemetry().init(rootDir);
100
+ }
101
+ setContext(context) {
102
+ return getTelemetry().setContext(context);
103
+ }
104
+ clearContext() {
105
+ return getTelemetry().clearContext();
106
+ }
107
+ getContext() {
108
+ return getTelemetry().getContext();
109
+ }
110
+ shouldPreserveSandbox(sandboxDir) {
111
+ return getTelemetry().shouldPreserveSandbox(sandboxDir);
112
+ }
113
+ };
114
+ var EnvironmentTelemetry = new TelemetryProxy();
115
+
116
+ // src/append-coordinator.ts
117
+ var AppendCoordinator = class _AppendCoordinator {
118
+ /**
119
+ * Safely appends a line to a JSONL log under process coordination locks.
120
+ * Performs an immediate fsync to ensure data durability.
121
+ * Also repairs the trailing line if it is corrupted, emitting an anomaly.
122
+ */
123
+ static appendAtomic(filePath, line, rootDir) {
124
+ const lockDir = path2.join(rootDir, ".hardkas", "locks");
125
+ if (!fs.existsSync(lockDir)) {
126
+ fs.mkdirSync(lockDir, { recursive: true });
127
+ }
128
+ const logBase = path2.basename(filePath);
129
+ const lockPath = path2.join(lockDir, `append-${logBase}.lock`);
130
+ let fd = null;
131
+ let repaired = false;
132
+ let linesDiscarded = 0;
133
+ let originalTail = "";
134
+ try {
135
+ const start = Date.now();
136
+ const timeoutMs = 1e4;
137
+ while (true) {
138
+ try {
139
+ fd = fs.openSync(lockPath, "wx");
140
+ break;
141
+ } catch (e) {
142
+ if (e.code === "EEXIST") {
143
+ if (Date.now() - start > timeoutMs) {
144
+ throw new Error(`[AppendCoordinator] Timeout waiting for lock on ${lockPath}`);
145
+ }
146
+ const sleepMs = 5 + Math.floor(Math.random() * 15);
147
+ const sharedBuf = new Int32Array(new SharedArrayBuffer(4));
148
+ Atomics.wait(sharedBuf, 0, 0, sleepMs);
149
+ continue;
150
+ }
151
+ throw e;
152
+ }
153
+ }
154
+ fs.writeSync(fd, JSON.stringify({ pid: process.pid, time: (/* @__PURE__ */ new Date()).toISOString() }));
155
+ const recovery = _AppendCoordinator.recoverCorruptedTail(filePath);
156
+ if (recovery.repaired) {
157
+ repaired = true;
158
+ linesDiscarded = recovery.linesDiscarded;
159
+ originalTail = recovery.originalTail;
160
+ }
161
+ const logDir = path2.dirname(filePath);
162
+ if (!fs.existsSync(logDir)) {
163
+ fs.mkdirSync(logDir, { recursive: true });
164
+ }
165
+ const logFd = fs.openSync(filePath, "a");
166
+ const buffer = Buffer.from(line.endsWith("\n") ? line : line + "\n", "utf-8");
167
+ fs.writeSync(logFd, buffer, 0, buffer.length);
168
+ fs.fsyncSync(logFd);
169
+ fs.closeSync(logFd);
170
+ } finally {
171
+ if (fd !== null) {
172
+ fs.closeSync(fd);
173
+ try {
174
+ fs.unlinkSync(lockPath);
175
+ } catch {
176
+ }
177
+ }
178
+ }
179
+ if (repaired) {
180
+ try {
181
+ const telemetry = getTelemetry();
182
+ telemetry.logAnomaly(
183
+ "EXTERNAL_MUTATION",
184
+ "medium",
185
+ "fs",
186
+ `Recovered corrupted trailing line in ${logBase}. Discarded ${linesDiscarded} malformed bytes. Original tail snippet: "${originalTail.slice(0, 60)}..."`,
187
+ rootDir
188
+ );
189
+ } catch {
190
+ }
191
+ }
192
+ }
193
+ /**
194
+ * Scans a JSONL stream for corruption, truncating malformed trailing lines.
195
+ */
196
+ static recoverCorruptedTail(filePath) {
197
+ if (!fs.existsSync(filePath)) return { repaired: false, linesDiscarded: 0, originalTail: "" };
198
+ const stat = fs.statSync(filePath);
199
+ if (stat.size === 0) return { repaired: false, linesDiscarded: 0, originalTail: "" };
200
+ const TAIL_SIZE = 4096;
201
+ const readStart = Math.max(0, stat.size - TAIL_SIZE);
202
+ const fd = fs.openSync(filePath, "r");
203
+ const buf = Buffer.alloc(Math.min(TAIL_SIZE, stat.size));
204
+ fs.readSync(fd, buf, 0, buf.length, readStart);
205
+ fs.closeSync(fd);
206
+ const tail = buf.toString("utf-8");
207
+ const lines = tail.split("\n");
208
+ if (lines.length === 0) return { repaired: false, linesDiscarded: 0, originalTail: "" };
209
+ let lastLine = "";
210
+ let lastLineIdx = -1;
211
+ for (let i = lines.length - 1; i >= 0; i--) {
212
+ const l = lines[i].trim();
213
+ if (l) {
214
+ lastLine = l;
215
+ lastLineIdx = i;
216
+ break;
217
+ }
218
+ }
219
+ if (!lastLine) return { repaired: false, linesDiscarded: 0, originalTail: "" };
220
+ if (readStart > 0 && lastLineIdx === 0) {
221
+ return { repaired: false, linesDiscarded: 0, originalTail: "" };
222
+ }
223
+ try {
224
+ JSON.parse(lastLine);
225
+ return { repaired: false, linesDiscarded: 0, originalTail: "" };
226
+ } catch (err) {
227
+ const linesAfterCorrupt = lines.slice(lastLineIdx).join("\n");
228
+ const bytesToRemove = Buffer.byteLength(linesAfterCorrupt, "utf-8");
229
+ const truncateTo = stat.size - bytesToRemove;
230
+ fs.truncateSync(filePath, truncateTo > 0 ? truncateTo : 0);
231
+ return {
232
+ repaired: true,
233
+ linesDiscarded: stat.size - truncateTo,
234
+ originalTail: lastLine
235
+ };
236
+ }
237
+ }
238
+ };
239
+
4
240
  // src/events.ts
241
+ import path3 from "path";
5
242
  var CoreEventBus = class {
6
243
  listeners = [];
7
244
  on(listener) {
@@ -37,13 +274,16 @@ var CoreEventBus = class {
37
274
  };
38
275
  var coreEvents = new CoreEventBus();
39
276
  function createEventEnvelope(params) {
277
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
40
278
  return {
41
279
  schema: "hardkas.event",
42
280
  version: "1.0.0",
43
281
  eventId: params.eventId || crypto.randomUUID(),
44
282
  domain: params.domain,
45
283
  kind: params.kind,
46
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
284
+ timestamp,
285
+ emittedAt: timestamp,
286
+ sourceSubsystem: params.sourceSubsystem,
47
287
  workflowId: params.workflowId,
48
288
  correlationId: params.correlationId,
49
289
  causationId: params.causationId,
@@ -51,7 +291,8 @@ function createEventEnvelope(params) {
51
291
  txId: params.txId,
52
292
  networkId: params.networkId,
53
293
  payload: params.payload,
54
- ...params.sequence !== void 0 ? { sequence: params.sequence } : {}
294
+ sequenceNumber: params.sequenceNumber,
295
+ globalOffset: params.globalOffset
55
296
  };
56
297
  }
57
298
  function validateEventEnvelope(event) {
@@ -62,6 +303,25 @@ function validateEventEnvelope(event) {
62
303
  if (typeof event.payload !== "object") return false;
63
304
  return true;
64
305
  }
306
+ function attachLedgerAppender(workspaceRoot) {
307
+ const seenEventIds = /* @__PURE__ */ new Set();
308
+ const eventsFile = path3.join(workspaceRoot, "events.jsonl");
309
+ return coreEvents.on((event) => {
310
+ if (seenEventIds.has(event.eventId)) {
311
+ return;
312
+ }
313
+ seenEventIds.add(event.eventId);
314
+ if (seenEventIds.size > 1e5) {
315
+ const iterator = seenEventIds.keys();
316
+ for (let i = 0; i < 1e4; i++) seenEventIds.delete(iterator.next().value);
317
+ }
318
+ const payload = JSON.stringify(event) + "\n";
319
+ try {
320
+ AppendCoordinator.appendAtomic(eventsFile, payload, workspaceRoot);
321
+ } catch (e) {
322
+ }
323
+ });
324
+ }
65
325
 
66
326
  // src/domain-types.ts
67
327
  var asTxId = (id) => id;
@@ -112,33 +372,35 @@ function redactSecret(value) {
112
372
  }
113
373
 
114
374
  // src/fs.ts
115
- import fs from "fs";
116
- import path from "path";
375
+ import fs2 from "fs";
376
+ import path4 from "path";
377
+ import crypto3 from "crypto";
117
378
  async function writeFileAtomic(targetPath, data, options = {}) {
118
- const dir = path.dirname(targetPath);
119
- const base = path.basename(targetPath);
120
- const tempPath = path.join(dir, `.tmp.${base}.${Math.random().toString(36).slice(2)}`);
379
+ const dir = path4.dirname(targetPath);
380
+ const base = path4.basename(targetPath);
381
+ const tempPath = path4.join(dir, `.tmp.${base}.${crypto3.randomUUID()}`);
121
382
  let fd = null;
122
383
  try {
123
- if (!fs.existsSync(dir)) {
124
- fs.mkdirSync(dir, { recursive: true });
384
+ if (!fs2.existsSync(dir)) {
385
+ fs2.mkdirSync(dir, { recursive: true });
125
386
  }
126
- fd = fs.openSync(tempPath, "w", options.mode);
387
+ fd = fs2.openSync(tempPath, "w", options.mode);
127
388
  const buffer = typeof data === "string" ? Buffer.from(data, options.encoding || "utf-8") : data;
128
- fs.writeSync(fd, buffer, 0, buffer.length);
129
- fs.fsyncSync(fd);
130
- fs.closeSync(fd);
389
+ fs2.writeSync(fd, buffer, 0, buffer.length);
390
+ fs2.fsyncSync(fd);
391
+ fs2.closeSync(fd);
131
392
  fd = null;
132
393
  let attempts = 0;
133
394
  const maxAttempts = process.platform === "win32" ? 5 : 1;
134
395
  while (attempts < maxAttempts) {
135
396
  try {
136
- fs.renameSync(tempPath, targetPath);
397
+ fs2.renameSync(tempPath, targetPath);
137
398
  break;
138
399
  } catch (e) {
139
400
  attempts++;
140
401
  if (attempts >= maxAttempts) throw e;
141
402
  if (e.code === "EPERM" || e.code === "EBUSY") {
403
+ EnvironmentTelemetry.logAnomaly("FS_RETRY", "low", "fs", `Retrying rename of ${targetPath} due to ${e.code}`);
142
404
  await new Promise((resolve) => setTimeout(resolve, 10 * attempts));
143
405
  continue;
144
406
  }
@@ -148,11 +410,11 @@ async function writeFileAtomic(targetPath, data, options = {}) {
148
410
  if (options.fsyncParent && process.platform !== "win32") {
149
411
  let dirFd = null;
150
412
  try {
151
- dirFd = fs.openSync(dir, "r");
152
- fs.fsyncSync(dirFd);
413
+ dirFd = fs2.openSync(dir, "r");
414
+ fs2.fsyncSync(dirFd);
153
415
  } catch (e) {
154
416
  } finally {
155
- if (dirFd !== null) fs.closeSync(dirFd);
417
+ if (dirFd !== null) fs2.closeSync(dirFd);
156
418
  }
157
419
  }
158
420
  } catch (err) {
@@ -162,45 +424,46 @@ async function writeFileAtomic(targetPath, data, options = {}) {
162
424
  { cause: err }
163
425
  );
164
426
  } finally {
165
- if (fs.existsSync(tempPath)) {
427
+ if (fs2.existsSync(tempPath)) {
166
428
  try {
167
- fs.unlinkSync(tempPath);
429
+ fs2.unlinkSync(tempPath);
168
430
  } catch (e) {
169
431
  }
170
432
  }
171
433
  if (fd !== null) {
172
434
  try {
173
- fs.closeSync(fd);
435
+ fs2.closeSync(fd);
174
436
  } catch (e) {
175
437
  }
176
438
  }
177
439
  }
178
440
  }
179
441
  function writeFileAtomicSync(targetPath, data, options = {}) {
180
- const dir = path.dirname(targetPath);
181
- const base = path.basename(targetPath);
182
- const tempPath = path.join(dir, `.tmp.${base}.${Math.random().toString(36).slice(2)}`);
442
+ const dir = path4.dirname(targetPath);
443
+ const base = path4.basename(targetPath);
444
+ const tempPath = path4.join(dir, `.tmp.${base}.${crypto3.randomUUID()}`);
183
445
  let fd = null;
184
446
  try {
185
- if (!fs.existsSync(dir)) {
186
- fs.mkdirSync(dir, { recursive: true });
447
+ if (!fs2.existsSync(dir)) {
448
+ fs2.mkdirSync(dir, { recursive: true });
187
449
  }
188
- fd = fs.openSync(tempPath, "w", options.mode);
450
+ fd = fs2.openSync(tempPath, "w", options.mode);
189
451
  const buffer = typeof data === "string" ? Buffer.from(data, options.encoding || "utf-8") : data;
190
- fs.writeSync(fd, buffer, 0, buffer.length);
191
- fs.fsyncSync(fd);
192
- fs.closeSync(fd);
452
+ fs2.writeSync(fd, buffer, 0, buffer.length);
453
+ fs2.fsyncSync(fd);
454
+ fs2.closeSync(fd);
193
455
  fd = null;
194
456
  let attempts = 0;
195
457
  const maxAttempts = process.platform === "win32" ? 5 : 1;
196
458
  while (attempts < maxAttempts) {
197
459
  try {
198
- fs.renameSync(tempPath, targetPath);
460
+ fs2.renameSync(tempPath, targetPath);
199
461
  break;
200
462
  } catch (e) {
201
463
  attempts++;
202
464
  if (attempts >= maxAttempts) throw e;
203
465
  if (e.code === "EPERM" || e.code === "EBUSY") {
466
+ EnvironmentTelemetry.logAnomaly("FS_RETRY", "low", "fs", `Retrying rename sync of ${targetPath} due to ${e.code}`);
204
467
  continue;
205
468
  }
206
469
  throw e;
@@ -209,11 +472,11 @@ function writeFileAtomicSync(targetPath, data, options = {}) {
209
472
  if (options.fsyncParent && process.platform !== "win32") {
210
473
  let dirFd = null;
211
474
  try {
212
- dirFd = fs.openSync(dir, "r");
213
- fs.fsyncSync(dirFd);
475
+ dirFd = fs2.openSync(dir, "r");
476
+ fs2.fsyncSync(dirFd);
214
477
  } catch (e) {
215
478
  } finally {
216
- if (dirFd !== null) fs.closeSync(dirFd);
479
+ if (dirFd !== null) fs2.closeSync(dirFd);
217
480
  }
218
481
  }
219
482
  } catch (err) {
@@ -223,15 +486,15 @@ function writeFileAtomicSync(targetPath, data, options = {}) {
223
486
  { cause: err }
224
487
  );
225
488
  } finally {
226
- if (fs.existsSync(tempPath)) {
489
+ if (fs2.existsSync(tempPath)) {
227
490
  try {
228
- fs.unlinkSync(tempPath);
491
+ fs2.unlinkSync(tempPath);
229
492
  } catch (e) {
230
493
  }
231
494
  }
232
495
  if (fd !== null) {
233
496
  try {
234
- fs.closeSync(fd);
497
+ fs2.closeSync(fd);
235
498
  } catch (e) {
236
499
  }
237
500
  }
@@ -257,8 +520,8 @@ function formatCorruptionIssue(issue) {
257
520
  }
258
521
 
259
522
  // src/lock.ts
260
- import fs2 from "fs";
261
- import path2 from "path";
523
+ import fs3 from "fs";
524
+ import path5 from "path";
262
525
  import os from "os";
263
526
  var LOCK_ORDER = [
264
527
  "workspace",
@@ -269,13 +532,14 @@ var LOCK_ORDER = [
269
532
  "query-store"
270
533
  ];
271
534
  async function acquireLock(args) {
272
- const lockDir = path2.join(args.rootDir, ".hardkas", "locks");
273
- const lockPath = path2.join(lockDir, `${args.name}.lock`);
535
+ const lockDir = path5.join(args.rootDir, ".hardkas", "locks");
536
+ const lockPath = path5.join(lockDir, `${args.name}.lock`);
274
537
  const timeoutMs = args.timeoutMs ?? 3e4;
275
538
  const pollMs = args.pollMs ?? 250;
276
539
  const start = Date.now();
277
- if (!fs2.existsSync(lockDir)) {
278
- fs2.mkdirSync(lockDir, { recursive: true });
540
+ let staleRecoveryAttempted = false;
541
+ if (!fs3.existsSync(lockDir)) {
542
+ fs3.mkdirSync(lockDir, { recursive: true });
279
543
  }
280
544
  while (true) {
281
545
  try {
@@ -289,18 +553,18 @@ async function acquireLock(args) {
289
553
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
290
554
  expiresAt: null
291
555
  };
292
- const fd = fs2.openSync(lockPath, "wx");
293
- fs2.writeSync(fd, JSON.stringify(metadata, null, 2));
294
- fs2.closeSync(fd);
556
+ const fd = fs3.openSync(lockPath, "wx");
557
+ fs3.writeSync(fd, JSON.stringify(metadata, null, 2));
558
+ fs3.closeSync(fd);
295
559
  return {
296
560
  path: lockPath,
297
561
  metadata,
298
562
  release: async () => {
299
- if (fs2.existsSync(lockPath)) {
563
+ if (fs3.existsSync(lockPath)) {
300
564
  try {
301
- const current = JSON.parse(fs2.readFileSync(lockPath, "utf-8"));
565
+ const current = JSON.parse(fs3.readFileSync(lockPath, "utf-8"));
302
566
  if (current.pid === process.pid) {
303
- fs2.unlinkSync(lockPath);
567
+ fs3.unlinkSync(lockPath);
304
568
  }
305
569
  } catch (e) {
306
570
  }
@@ -311,12 +575,49 @@ async function acquireLock(args) {
311
575
  if (e.code === "EEXIST") {
312
576
  let existingMetadata = null;
313
577
  try {
314
- existingMetadata = JSON.parse(fs2.readFileSync(lockPath, "utf-8"));
578
+ existingMetadata = JSON.parse(fs3.readFileSync(lockPath, "utf-8"));
315
579
  } catch (err) {
580
+ const LOCK_CREATION_GRACE_MS = 2e3;
581
+ let stats = null;
582
+ try {
583
+ stats = fs3.statSync(lockPath);
584
+ } catch {
585
+ continue;
586
+ }
587
+ const ageMs = Date.now() - stats.mtimeMs;
588
+ if (ageMs < LOCK_CREATION_GRACE_MS) {
589
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
590
+ continue;
591
+ }
592
+ if (!staleRecoveryAttempted) {
593
+ staleRecoveryAttempted = true;
594
+ try {
595
+ fs3.unlinkSync(lockPath);
596
+ EnvironmentTelemetry.logAnomaly("STALE_LOCK_RECOVERY", "medium", "lock", `Recovered corrupted lock file at ${lockPath} (Age: ${ageMs}ms)`, args.rootDir);
597
+ continue;
598
+ } catch {
599
+ throw new HardkasError("LOCK_METADATA_INVALID", `Lock file at ${lockPath} is corrupted and cannot be recovered.`, { cause: err });
600
+ }
601
+ }
316
602
  throw new HardkasError("LOCK_METADATA_INVALID", `Lock file at ${lockPath} is corrupted.`, { cause: err });
317
603
  }
318
604
  if (existingMetadata) {
319
- const isAlive = isProcessAlive(existingMetadata.pid);
605
+ const isLocal = existingMetadata.hostname === os.hostname();
606
+ const isAlive = isLocal ? isProcessAlive(existingMetadata.pid) : true;
607
+ if (!isAlive && !staleRecoveryAttempted) {
608
+ staleRecoveryAttempted = true;
609
+ try {
610
+ fs3.unlinkSync(lockPath);
611
+ EnvironmentTelemetry.logAnomaly("STALE_LOCK_RECOVERY", "medium", "lock", `Recovered lock held by dead process (PID: ${existingMetadata.pid})`, args.rootDir);
612
+ continue;
613
+ } catch (unlinkErr) {
614
+ throw new HardkasError(
615
+ "STALE_LOCK",
616
+ `Workspace is locked by a dead process (PID: ${existingMetadata.pid}). Failed to auto-recover: ${unlinkErr}`,
617
+ { cause: existingMetadata }
618
+ );
619
+ }
620
+ }
320
621
  if (!isAlive) {
321
622
  throw new HardkasError(
322
623
  "STALE_LOCK",
@@ -325,6 +626,7 @@ async function acquireLock(args) {
325
626
  );
326
627
  }
327
628
  if (args.wait && Date.now() - start < timeoutMs) {
629
+ EnvironmentTelemetry.logAnomaly("LOCK_CONTENTION", "low", "lock", `Waiting for lock ${args.name} held by PID ${existingMetadata.pid}`, args.rootDir);
328
630
  await new Promise((resolve) => setTimeout(resolve, pollMs));
329
631
  continue;
330
632
  }
@@ -370,20 +672,22 @@ function isProcessAlive(pid) {
370
672
  process.kill(pid, 0);
371
673
  return true;
372
674
  } catch (e) {
373
- return e.code !== "ESRCH";
675
+ if (e.code === "EPERM") return true;
676
+ if (e.code === "ESRCH") return false;
677
+ return true;
374
678
  }
375
679
  }
376
680
  function listLocks(rootDir) {
377
- const lockDir = path2.join(rootDir, ".hardkas", "locks");
378
- if (!fs2.existsSync(lockDir)) return [];
379
- const files = fs2.readdirSync(lockDir).filter((f) => f.endsWith(".lock"));
681
+ const lockDir = path5.join(rootDir, ".hardkas", "locks");
682
+ if (!fs3.existsSync(lockDir)) return [];
683
+ const files = fs3.readdirSync(lockDir).filter((f) => f.endsWith(".lock"));
380
684
  const result = [];
381
685
  for (const file of files) {
382
- const lockPath = path2.join(lockDir, file);
686
+ const lockPath = path5.join(lockDir, file);
383
687
  try {
384
- const metadata = JSON.parse(fs2.readFileSync(lockPath, "utf-8"));
688
+ const metadata = JSON.parse(fs3.readFileSync(lockPath, "utf-8"));
385
689
  result.push({
386
- name: path2.basename(file, ".lock"),
690
+ name: path5.basename(file, ".lock"),
387
691
  metadata,
388
692
  path: lockPath,
389
693
  isAlive: metadata.hostname === os.hostname() ? isProcessAlive(metadata.pid) : true
@@ -395,15 +699,15 @@ function listLocks(rootDir) {
395
699
  return result;
396
700
  }
397
701
  function clearLock(rootDir, name, options = {}) {
398
- const lockDir = path2.join(rootDir, ".hardkas", "locks");
399
- const lockPath = path2.join(lockDir, `${name}.lock`);
400
- if (!fs2.existsSync(lockPath)) return { cleared: false, reason: "Lock not found" };
702
+ const lockDir = path5.join(rootDir, ".hardkas", "locks");
703
+ const lockPath = path5.join(lockDir, `${name}.lock`);
704
+ if (!fs3.existsSync(lockPath)) return { cleared: false, reason: "Lock not found" };
401
705
  let metadata;
402
706
  try {
403
- metadata = JSON.parse(fs2.readFileSync(lockPath, "utf-8"));
707
+ metadata = JSON.parse(fs3.readFileSync(lockPath, "utf-8"));
404
708
  } catch (e) {
405
709
  if (options.force) {
406
- fs2.unlinkSync(lockPath);
710
+ fs3.unlinkSync(lockPath);
407
711
  return { cleared: true };
408
712
  }
409
713
  return { cleared: false, reason: "Corrupt metadata (use --force to clear)" };
@@ -416,10 +720,417 @@ function clearLock(rootDir, name, options = {}) {
416
720
  } else if (!options.force) {
417
721
  return { cleared: false, reason: "Lock is potentially active. Use --force or --if-dead." };
418
722
  }
419
- fs2.unlinkSync(lockPath);
723
+ fs3.unlinkSync(lockPath);
420
724
  return { cleared: true };
421
725
  }
422
726
 
727
+ // src/replay.ts
728
+ function diffReplays(replayA, replayB) {
729
+ const diff = {
730
+ schema: "hardkas.replayDiff.v1",
731
+ structural: {
732
+ missingArtifacts: [],
733
+ excludedArtifacts: [],
734
+ missingProjections: []
735
+ },
736
+ deterministic: {
737
+ stateRootDiverged: false,
738
+ lineageDiverged: false,
739
+ graphDiverged: false,
740
+ differences: []
741
+ },
742
+ observational: {
743
+ timestampShifts: [],
744
+ eventOrderingShifts: [],
745
+ metadataDrift: []
746
+ }
747
+ };
748
+ if (replayA.artifacts?.length !== replayB.artifacts?.length) {
749
+ diff.structural.missingArtifacts.push("artifact_count_mismatch");
750
+ }
751
+ const stateA = replayA.stateRoot || replayA.postStateHash;
752
+ const stateB = replayB.stateRoot || replayB.postStateHash;
753
+ if (stateA !== stateB) {
754
+ diff.deterministic.stateRootDiverged = true;
755
+ diff.deterministic.differences.push({
756
+ path: "stateRoot",
757
+ a: stateA,
758
+ b: stateB
759
+ });
760
+ }
761
+ if (replayA.amountSompi !== void 0 && replayB.amountSompi !== void 0 && replayA.amountSompi !== replayB.amountSompi) {
762
+ diff.deterministic.differences.push({
763
+ path: "amountSompi",
764
+ a: replayA.amountSompi,
765
+ b: replayB.amountSompi
766
+ });
767
+ }
768
+ const tsA = replayA.timestamp || replayA.createdAt;
769
+ const tsB = replayB.timestamp || replayB.createdAt;
770
+ if (tsA && tsB) {
771
+ const timeA = new Date(tsA).getTime();
772
+ const timeB = new Date(tsB).getTime();
773
+ if (timeA !== timeB) {
774
+ diff.observational.timestampShifts.push({ path: "timestamp", shiftMs: Math.abs(timeA - timeB) });
775
+ }
776
+ }
777
+ return diff;
778
+ }
779
+
780
+ // src/snapshot.ts
781
+ import fs4 from "fs/promises";
782
+ import path6 from "path";
783
+ async function createSnapshot(options) {
784
+ const { hardkasDir, outputDir, deterministicScope = "local-only" } = options;
785
+ await fs4.mkdir(outputDir, { recursive: true });
786
+ await fs4.mkdir(path6.join(outputDir, "artifacts"), { recursive: true });
787
+ await fs4.mkdir(path6.join(outputDir, "projections"), { recursive: true });
788
+ await fs4.mkdir(path6.join(outputDir, "events"), { recursive: true });
789
+ await fs4.mkdir(path6.join(outputDir, "replay"), { recursive: true });
790
+ await fs4.mkdir(path6.join(outputDir, "metadata"), { recursive: true });
791
+ let included = 0;
792
+ let excluded = 0;
793
+ let corrupted = 0;
794
+ const artifactsDir = path6.join(hardkasDir, "artifacts");
795
+ try {
796
+ const list = await fs4.readdir(artifactsDir);
797
+ for (const f of list) {
798
+ if (f.endsWith(".json")) {
799
+ const src = path6.join(artifactsDir, f);
800
+ const dest = path6.join(outputDir, "artifacts", f);
801
+ try {
802
+ const content = await fs4.readFile(src, "utf-8");
803
+ const parsed = JSON.parse(content);
804
+ if (parsed.schema && parsed.schema.startsWith("hardkas.")) {
805
+ await fs4.copyFile(src, dest);
806
+ included++;
807
+ } else {
808
+ excluded++;
809
+ }
810
+ } catch {
811
+ corrupted++;
812
+ }
813
+ }
814
+ }
815
+ } catch {
816
+ }
817
+ try {
818
+ const eventsLog = path6.join(hardkasDir, "events.jsonl");
819
+ await fs4.copyFile(eventsLog, path6.join(outputDir, "events", "events.jsonl"));
820
+ } catch {
821
+ }
822
+ try {
823
+ const dbPath = path6.join(hardkasDir, "store.db");
824
+ await fs4.copyFile(dbPath, path6.join(outputDir, "projections", "store.db"));
825
+ } catch {
826
+ }
827
+ const manifest = {
828
+ snapshotVersion: 1,
829
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
830
+ hardkasVersion: "0.6.1-alpha",
831
+ stateAuthority: "filesystem",
832
+ projectionAuthority: "sqlite",
833
+ deterministicScope,
834
+ consensusValidated: deterministicScope === "consensus-validated",
835
+ includedArtifacts: included,
836
+ excludedArtifacts: excluded,
837
+ corruptedArtifacts: corrupted
838
+ };
839
+ await fs4.writeFile(
840
+ path6.join(outputDir, "manifest.json"),
841
+ JSON.stringify(manifest, null, 2),
842
+ "utf-8"
843
+ );
844
+ return manifest;
845
+ }
846
+ async function readSnapshotManifest(snapshotDir) {
847
+ const manifestPath = path6.join(snapshotDir, "manifest.json");
848
+ const content = await fs4.readFile(manifestPath, "utf-8");
849
+ return JSON.parse(content);
850
+ }
851
+
852
+ // src/deterministic.ts
853
+ function deterministicCompare(a, b) {
854
+ return a < b ? -1 : a > b ? 1 : 0;
855
+ }
856
+
857
+ // src/retention.ts
858
+ import fs5 from "fs";
859
+ import path7 from "path";
860
+ var TelemetryRotator = class {
861
+ static DEFAULT_MAX_SIZE_BYTES = 10 * 1024 * 1024;
862
+ // 10MB
863
+ /**
864
+ * Rotates the telemetry stream if it exceeds the maximum size.
865
+ * This is a safe operation that renames the active file to an archive directory.
866
+ */
867
+ static rotateIfNeeded(rootDir, maxSizeBytes = this.DEFAULT_MAX_SIZE_BYTES) {
868
+ const telemetryDir = path7.join(rootDir, ".hardkas", "telemetry");
869
+ const activeFile = path7.join(telemetryDir, "telemetry.jsonl");
870
+ if (!fs5.existsSync(activeFile)) {
871
+ return { rotated: false, reason: "File does not exist" };
872
+ }
873
+ const stats = fs5.statSync(activeFile);
874
+ if (stats.size < maxSizeBytes) {
875
+ return { rotated: false, reason: `File size (${stats.size}) is below threshold (${maxSizeBytes})` };
876
+ }
877
+ return this.forceRotate(rootDir);
878
+ }
879
+ /**
880
+ * Forces a rotation regardless of file size.
881
+ */
882
+ static forceRotate(rootDir) {
883
+ const telemetryDir = path7.join(rootDir, ".hardkas", "telemetry");
884
+ const activeFile = path7.join(telemetryDir, "telemetry.jsonl");
885
+ if (!fs5.existsSync(activeFile)) {
886
+ return { rotated: false, reason: "File does not exist" };
887
+ }
888
+ const archiveDir = path7.join(telemetryDir, "archive");
889
+ if (!fs5.existsSync(archiveDir)) {
890
+ fs5.mkdirSync(archiveDir, { recursive: true });
891
+ }
892
+ const stats = fs5.statSync(activeFile);
893
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
894
+ const archiveFile = path7.join(archiveDir, `telemetry-${timestamp}.jsonl`);
895
+ try {
896
+ fs5.renameSync(activeFile, archiveFile);
897
+ return {
898
+ rotated: true,
899
+ archivePath: archiveFile,
900
+ bytesRotated: stats.size
901
+ };
902
+ } catch (err) {
903
+ return { rotated: false, reason: `Rename failed: ${err.message}` };
904
+ }
905
+ }
906
+ /**
907
+ * Lists all archived telemetry segments.
908
+ */
909
+ static listArchivedSegments(rootDir) {
910
+ const archiveDir = path7.join(rootDir, ".hardkas", "telemetry", "archive");
911
+ if (!fs5.existsSync(archiveDir)) return [];
912
+ return fs5.readdirSync(archiveDir).filter((f) => f.startsWith("telemetry-") && f.endsWith(".jsonl")).sort();
913
+ }
914
+ };
915
+
916
+ // src/runtime-context.ts
917
+ var systemRuntimeContext = {
918
+ clock: {
919
+ now: () => Date.now()
920
+ },
921
+ random: {
922
+ next: () => Math.random()
923
+ },
924
+ ids: {
925
+ execution: () => `exec_${Date.now().toString(36)}`,
926
+ workflow: () => `wf_${Date.now().toString(36)}`
927
+ },
928
+ telemetry: globalTelemetry
929
+ };
930
+
931
+ // src/semantics/status.ts
932
+ var LEGAL_TRANSITIONS = {
933
+ UNKNOWN: ["PROJECTED", "QUARANTINED", "CORRUPTED"],
934
+ PROJECTED: ["VERIFIED", "CORRUPTED"],
935
+ VERIFIED: ["STALE", "REPLAY_VERIFIED", "CORRUPTED"],
936
+ STALE: ["VERIFIED", "REPLAY_VERIFIED", "CORRUPTED"],
937
+ REPLAY_VERIFIED: ["STALE", "CORRUPTED"],
938
+ CORRUPTED: ["QUARANTINED"],
939
+ QUARANTINED: []
940
+ // Terminal state
941
+ };
942
+ function validateStatusTransition(from, to) {
943
+ if (from === to) return;
944
+ const allowed = LEGAL_TRANSITIONS[from];
945
+ if (!allowed.includes(to)) {
946
+ throw new Error(
947
+ `[CRITICAL SEMANTIC ERROR] Illegal artifact status transition attempted: ${from} -> ${to}. This is a violation of the semantic artifact status lattice.`
948
+ );
949
+ }
950
+ }
951
+
952
+ // src/semantics/api.ts
953
+ function resolveCanonicalArtifact(params) {
954
+ if (!params.artifactId && !params.lineageId && !params.semanticHash) {
955
+ throw new Error(
956
+ `[CRITICAL SEMANTIC ERROR] Implicit resolution forbidden. You must pin resolution by providing an explicit artifactId, lineageId, or semanticHash.`
957
+ );
958
+ }
959
+ return params.artifactId || params.semanticHash || params.lineageId || "";
960
+ }
961
+ function verifyArtifactIntegrity(identity, computedHash) {
962
+ if (identity.semanticHash !== computedHash) {
963
+ throw new Error(
964
+ `[CRITICAL SEMANTIC ERROR] Integrity mismatch for artifact ${identity.artifactId}: expected hash ${identity.semanticHash}, got ${computedHash}`
965
+ );
966
+ }
967
+ }
968
+ function verifyReplay(identity, replayCtx) {
969
+ if (identity.semanticHash !== replayCtx.semanticHash) {
970
+ throw new Error(`[CRITICAL SEMANTIC ERROR] Replay semantic hash divergence: expected ${identity.semanticHash}, got ${replayCtx.semanticHash}`);
971
+ }
972
+ validateStatusTransition(identity.status, "REPLAY_VERIFIED");
973
+ return "REPLAY_VERIFIED";
974
+ }
975
+ function verifyProjectionFreshness(identity, currentLineageHead) {
976
+ return true;
977
+ }
978
+ function classifyArtifactStatus(identity, isReadable, isCorrupted) {
979
+ if (isCorrupted) return "CORRUPTED";
980
+ if (!isReadable) return "UNKNOWN";
981
+ if (identity.status === "UNKNOWN") return "PROJECTED";
982
+ return identity.status;
983
+ }
984
+ function resolveLineage(artifactId) {
985
+ return [artifactId];
986
+ }
987
+ function verifyCapabilityBoundary(identity, capability) {
988
+ }
989
+
990
+ // src/semantics/migration.ts
991
+ function verifyMigrationIntegrity(preMigration, postMigration) {
992
+ if (preMigration.artifactId !== postMigration.artifactId) {
993
+ throw new Error(`[CRITICAL SEMANTIC ERROR] Migration unexpectedly altered canonical artifact ID: ${preMigration.artifactId} -> ${postMigration.artifactId}`);
994
+ }
995
+ if (postMigration.schemaVersion < preMigration.schemaVersion) {
996
+ throw new Error(`[CRITICAL SEMANTIC ERROR] Invalid migration: schema downgraded from ${preMigration.schemaVersion} to ${postMigration.schemaVersion}`);
997
+ }
998
+ }
999
+ function migrateArtifact(identity, targetVersion) {
1000
+ if (identity.schemaVersion === targetVersion) {
1001
+ return { migratedIdentity: identity, success: true };
1002
+ }
1003
+ return {
1004
+ migratedIdentity: identity,
1005
+ success: false,
1006
+ error: `No migration path from ${identity.schemaVersion} to ${targetVersion}`
1007
+ };
1008
+ }
1009
+ function comparePrePostMigrationLineage(preLineageId, postLineageId) {
1010
+ if (preLineageId !== postLineageId) {
1011
+ throw new Error(`[CRITICAL SEMANTIC ERROR] Lineage broken across schema migration: ${preLineageId} -> ${postLineageId}`);
1012
+ }
1013
+ }
1014
+
1015
+ // src/semantics/drift.ts
1016
+ function detectSemanticDrift(dashboardView, queryStoreView, replayView, filesystemView) {
1017
+ const views = {
1018
+ Dashboard: dashboardView,
1019
+ QueryStore: queryStoreView,
1020
+ Replay: replayView,
1021
+ Filesystem: filesystemView
1022
+ };
1023
+ let referenceView = filesystemView;
1024
+ for (const [subsystem, view] of Object.entries(views)) {
1025
+ if (view.semanticHash !== referenceView.semanticHash) {
1026
+ return {
1027
+ hasDrift: true,
1028
+ conflictingSubsystem: subsystem,
1029
+ exactReplayCommand: `hardkas verify-replay --artifact ${referenceView.artifactId}`,
1030
+ severity: "CRITICAL",
1031
+ details: `Hash mismatch: ${subsystem} (${view.semanticHash}) vs Reference (${referenceView.semanticHash})`
1032
+ };
1033
+ }
1034
+ if (view.status !== referenceView.status) {
1035
+ if (subsystem === "Dashboard" && view.status === "VERIFIED" && replayView.status === "STALE") {
1036
+ return {
1037
+ hasDrift: true,
1038
+ conflictingSubsystem: subsystem,
1039
+ exactReplayCommand: `hardkas verify-replay --artifact ${referenceView.artifactId}`,
1040
+ severity: "CRITICAL",
1041
+ details: `Dashboard claims VERIFIED but Replay claims STALE.`
1042
+ };
1043
+ }
1044
+ }
1045
+ }
1046
+ return { hasDrift: false, severity: "NONE" };
1047
+ }
1048
+ function assertNoSemanticDrift(dashboardView, queryStoreView, replayView, filesystemView) {
1049
+ const report = detectSemanticDrift(dashboardView, queryStoreView, replayView, filesystemView);
1050
+ if (report.hasDrift) {
1051
+ throw new Error(
1052
+ `[CRITICAL SEMANTIC DRIFT] Subsystem disagreement detected.
1053
+ Conflicting Subsystem: ${report.conflictingSubsystem}
1054
+ Details: ${report.details}
1055
+ Resolution Command: ${report.exactReplayCommand}`
1056
+ );
1057
+ }
1058
+ }
1059
+
1060
+ // src/migrations.ts
1061
+ import fs6 from "fs";
1062
+ import path8 from "path";
1063
+ var CURRENT_RUNTIME_VERSION = "0.6.1-alpha";
1064
+ var MIN_SUPPORTED_VERSION = "0.5.0-alpha";
1065
+ var MigrationManager = class {
1066
+ static checkVersion(rootDir) {
1067
+ const versionFile = path8.join(rootDir, ".hardkas", "version.json");
1068
+ if (!fs6.existsSync(versionFile)) {
1069
+ this.writeVersion(rootDir, CURRENT_RUNTIME_VERSION);
1070
+ return { needsMigration: false, canDowngrade: true, currentVersion: CURRENT_RUNTIME_VERSION };
1071
+ }
1072
+ try {
1073
+ const data = JSON.parse(fs6.readFileSync(versionFile, "utf-8"));
1074
+ const wsVersion = data.runtimeVersion || "0.0.0";
1075
+ if (wsVersion === CURRENT_RUNTIME_VERSION) {
1076
+ return { needsMigration: false, canDowngrade: true, currentVersion: wsVersion };
1077
+ }
1078
+ if (this.compareSemver(wsVersion, CURRENT_RUNTIME_VERSION) > 0) {
1079
+ return { needsMigration: false, canDowngrade: false, currentVersion: wsVersion };
1080
+ }
1081
+ if (this.compareSemver(wsVersion, MIN_SUPPORTED_VERSION) < 0) {
1082
+ throw new HardkasError("MIGRATION_UNSUPPORTED", `Workspace version ${wsVersion} is too old to migrate to ${CURRENT_RUNTIME_VERSION}`);
1083
+ }
1084
+ return { needsMigration: true, canDowngrade: true, currentVersion: wsVersion };
1085
+ } catch (err) {
1086
+ if (err instanceof HardkasError) throw err;
1087
+ throw new HardkasError("MIGRATION_ERROR", `Failed to parse version.json: ${err.message}`);
1088
+ }
1089
+ }
1090
+ static migrate(rootDir, dryRun = false) {
1091
+ const status = this.checkVersion(rootDir);
1092
+ if (!status.canDowngrade) {
1093
+ throw new HardkasError("DOWNGRADE_REFUSED", `Cannot safely downgrade from workspace version ${status.currentVersion} to runtime version ${CURRENT_RUNTIME_VERSION}.`);
1094
+ }
1095
+ if (!status.needsMigration) return;
1096
+ if (dryRun) {
1097
+ console.log(`[DRY-RUN] Would migrate workspace from ${status.currentVersion} to ${CURRENT_RUNTIME_VERSION}`);
1098
+ return;
1099
+ }
1100
+ this.backupWorkspace(rootDir);
1101
+ try {
1102
+ this.writeVersion(rootDir, CURRENT_RUNTIME_VERSION);
1103
+ } catch (err) {
1104
+ getTelemetry().logAnomaly("EXTERNAL_MUTATION", "critical", "projection", `Migration failed: ${err.message}`);
1105
+ throw new HardkasError("MIGRATION_FAILED", `Migration failed, workspace might be corrupted: ${err.message}`);
1106
+ }
1107
+ }
1108
+ static writeVersion(rootDir, version) {
1109
+ const versionFile = path8.join(rootDir, ".hardkas", "version.json");
1110
+ if (!fs6.existsSync(path8.dirname(versionFile))) {
1111
+ fs6.mkdirSync(path8.dirname(versionFile), { recursive: true });
1112
+ }
1113
+ fs6.writeFileSync(versionFile, JSON.stringify({ runtimeVersion: version }, null, 2));
1114
+ }
1115
+ static backupWorkspace(rootDir) {
1116
+ const hardkasDir = path8.join(rootDir, ".hardkas");
1117
+ const backupDir = path8.join(rootDir, `.hardkas-backup-${Date.now()}`);
1118
+ if (fs6.existsSync(hardkasDir)) {
1119
+ fs6.cpSync(hardkasDir, backupDir, { recursive: true });
1120
+ }
1121
+ }
1122
+ static compareSemver(v1, v2) {
1123
+ const parse = (v) => v.replace("-alpha", "").split(".").map(Number);
1124
+ const p1 = parse(v1);
1125
+ const p2 = parse(v2);
1126
+ for (let i = 0; i < 3; i++) {
1127
+ if ((p1[i] || 0) > (p2[i] || 0)) return 1;
1128
+ if ((p1[i] || 0) < (p2[i] || 0)) return -1;
1129
+ }
1130
+ return 0;
1131
+ }
1132
+ };
1133
+
423
1134
  // src/index.ts
424
1135
  var SOMPI_PER_KAS = 100000000n;
425
1136
  var kaspaNetworkIdSchema = z.enum([
@@ -429,7 +1140,8 @@ var kaspaNetworkIdSchema = z.enum([
429
1140
  "testnet-12",
430
1141
  "simnet",
431
1142
  "simnet-1",
432
- "devnet"
1143
+ "devnet",
1144
+ "simulated"
433
1145
  ]);
434
1146
  var executionModeSchema = z.enum([
435
1147
  "simulated",
@@ -441,7 +1153,8 @@ var artifactTypeSchema = z.enum([
441
1153
  "signedTx",
442
1154
  "txReceipt",
443
1155
  "txTrace",
444
- "snapshot"
1156
+ "snapshot",
1157
+ "workflow.v1"
445
1158
  ]);
446
1159
  var NetworkIdSchema = kaspaNetworkIdSchema;
447
1160
  var ExecutionModeSchema = executionModeSchema;
@@ -510,13 +1223,20 @@ function formatSompi(amountSompi) {
510
1223
  return `${sign}${whole}.${fractional.toString().padStart(8, "0")} KAS`;
511
1224
  }
512
1225
  export {
1226
+ AppendCoordinator,
513
1227
  ArtifactTypeSchema,
1228
+ CURRENT_RUNTIME_VERSION,
1229
+ EnvironmentTelemetry,
514
1230
  ExecutionModeSchema,
515
1231
  HardkasError,
516
1232
  InvariantViolationError,
517
1233
  LOCK_ORDER,
1234
+ MIN_SUPPORTED_VERSION,
1235
+ MigrationManager,
518
1236
  NetworkIdSchema,
519
1237
  SOMPI_PER_KAS,
1238
+ TelemetryManager,
1239
+ TelemetryRotator,
520
1240
  acquireLock,
521
1241
  artifactTypeSchema,
522
1242
  asArtifactId,
@@ -531,21 +1251,43 @@ export {
531
1251
  asRpcEndpointId,
532
1252
  asTxId,
533
1253
  asWorkflowId,
1254
+ assertNoSemanticDrift,
1255
+ attachLedgerAppender,
1256
+ classifyArtifactStatus,
534
1257
  clearLock,
1258
+ comparePrePostMigrationLineage,
535
1259
  coreEvents,
536
1260
  createEventEnvelope,
1261
+ createSnapshot,
1262
+ detectSemanticDrift,
1263
+ deterministicCompare,
1264
+ diffReplays,
537
1265
  executionModeSchema,
538
1266
  formatCorruptionIssue,
539
1267
  formatSompi,
1268
+ getTelemetry,
1269
+ globalTelemetry,
540
1270
  hardkasConfigSchema,
541
1271
  isProcessAlive,
542
1272
  kaspaNetworkIdSchema,
543
1273
  listLocks,
544
1274
  maskSecrets,
1275
+ migrateArtifact,
545
1276
  parseHardkasConfig,
546
1277
  parseKasToSompi,
1278
+ readSnapshotManifest,
547
1279
  redactSecret,
1280
+ resolveCanonicalArtifact,
1281
+ resolveLineage,
1282
+ systemRuntimeContext,
1283
+ telemetryContextStorage,
548
1284
  validateEventEnvelope,
1285
+ validateStatusTransition,
1286
+ verifyArtifactIntegrity,
1287
+ verifyCapabilityBoundary,
1288
+ verifyMigrationIntegrity,
1289
+ verifyProjectionFreshness,
1290
+ verifyReplay,
549
1291
  withLock,
550
1292
  withLocks,
551
1293
  writeFileAtomic,