caveat-cli 0.16.2 → 0.17.0
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-3MLJQLWY.js → chunk-7FEOFAMA.js} +479 -112
- package/dist/chunk-7FEOFAMA.js.map +1 -0
- package/dist/index.js +522 -221
- package/dist/index.js.map +1 -1
- package/dist/{server-LAJCQXS3.js → server-STR2EAWZ.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-3MLJQLWY.js.map +0 -1
- /package/dist/{server-LAJCQXS3.js.map → server-STR2EAWZ.js.map} +0 -0
|
@@ -2721,7 +2721,7 @@ var require_dumper = __commonJS({
|
|
|
2721
2721
|
var hasFoldableLine = false;
|
|
2722
2722
|
var shouldTrackWidth = lineWidth !== -1;
|
|
2723
2723
|
var previousLineBreak = -1;
|
|
2724
|
-
var
|
|
2724
|
+
var plain2 = isPlainSafeFirst2(string.charCodeAt(0)) && !isWhitespace2(string.charCodeAt(string.length - 1));
|
|
2725
2725
|
if (singleLineOnly) {
|
|
2726
2726
|
for (i2 = 0; i2 < string.length; i2++) {
|
|
2727
2727
|
char = string.charCodeAt(i2);
|
|
@@ -2729,7 +2729,7 @@ var require_dumper = __commonJS({
|
|
|
2729
2729
|
return STYLE_DOUBLE2;
|
|
2730
2730
|
}
|
|
2731
2731
|
prev_char = i2 > 0 ? string.charCodeAt(i2 - 1) : null;
|
|
2732
|
-
|
|
2732
|
+
plain2 = plain2 && isPlainSafe2(char, prev_char);
|
|
2733
2733
|
}
|
|
2734
2734
|
} else {
|
|
2735
2735
|
for (i2 = 0; i2 < string.length; i2++) {
|
|
@@ -2745,12 +2745,12 @@ var require_dumper = __commonJS({
|
|
|
2745
2745
|
return STYLE_DOUBLE2;
|
|
2746
2746
|
}
|
|
2747
2747
|
prev_char = i2 > 0 ? string.charCodeAt(i2 - 1) : null;
|
|
2748
|
-
|
|
2748
|
+
plain2 = plain2 && isPlainSafe2(char, prev_char);
|
|
2749
2749
|
}
|
|
2750
2750
|
hasFoldableLine = hasFoldableLine || shouldTrackWidth && (i2 - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " ");
|
|
2751
2751
|
}
|
|
2752
2752
|
if (!hasLineBreak && !hasFoldableLine) {
|
|
2753
|
-
return
|
|
2753
|
+
return plain2 && !testAmbiguousType(string) ? STYLE_PLAIN2 : STYLE_SINGLE2;
|
|
2754
2754
|
}
|
|
2755
2755
|
if (indentPerLevel > 9 && needIndentIndicator2(string)) {
|
|
2756
2756
|
return STYLE_DOUBLE2;
|
|
@@ -6112,7 +6112,7 @@ var require_semver2 = __commonJS({
|
|
|
6112
6112
|
"../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/index.js"(exports2, module2) {
|
|
6113
6113
|
"use strict";
|
|
6114
6114
|
var internalRe = require_re();
|
|
6115
|
-
var
|
|
6115
|
+
var constants2 = require_constants();
|
|
6116
6116
|
var SemVer = require_semver();
|
|
6117
6117
|
var identifiers = require_identifiers();
|
|
6118
6118
|
var parse2 = require_parse2();
|
|
@@ -6194,8 +6194,8 @@ var require_semver2 = __commonJS({
|
|
|
6194
6194
|
re: internalRe.re,
|
|
6195
6195
|
src: internalRe.src,
|
|
6196
6196
|
tokens: internalRe.t,
|
|
6197
|
-
SEMVER_SPEC_VERSION:
|
|
6198
|
-
RELEASE_TYPES:
|
|
6197
|
+
SEMVER_SPEC_VERSION: constants2.SEMVER_SPEC_VERSION,
|
|
6198
|
+
RELEASE_TYPES: constants2.RELEASE_TYPES,
|
|
6199
6199
|
compareIdentifiers: identifiers.compareIdentifiers,
|
|
6200
6200
|
rcompareIdentifiers: identifiers.rcompareIdentifiers
|
|
6201
6201
|
};
|
|
@@ -8367,14 +8367,14 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, te
|
|
|
8367
8367
|
var hasFoldableLine = false;
|
|
8368
8368
|
var shouldTrackWidth = lineWidth !== -1;
|
|
8369
8369
|
var previousLineBreak = -1;
|
|
8370
|
-
var
|
|
8370
|
+
var plain2 = isPlainSafeFirst(codePointAt(string, 0)) && isPlainSafeLast(codePointAt(string, string.length - 1));
|
|
8371
8371
|
if (singleLineOnly || forceQuotes) {
|
|
8372
8372
|
for (i2 = 0; i2 < string.length; char >= 65536 ? i2 += 2 : i2++) {
|
|
8373
8373
|
char = codePointAt(string, i2);
|
|
8374
8374
|
if (!isPrintable(char)) {
|
|
8375
8375
|
return STYLE_DOUBLE;
|
|
8376
8376
|
}
|
|
8377
|
-
|
|
8377
|
+
plain2 = plain2 && isPlainSafe(char, prevChar, inblock);
|
|
8378
8378
|
prevChar = char;
|
|
8379
8379
|
}
|
|
8380
8380
|
} else {
|
|
@@ -8390,13 +8390,13 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, te
|
|
|
8390
8390
|
} else if (!isPrintable(char)) {
|
|
8391
8391
|
return STYLE_DOUBLE;
|
|
8392
8392
|
}
|
|
8393
|
-
|
|
8393
|
+
plain2 = plain2 && isPlainSafe(char, prevChar, inblock);
|
|
8394
8394
|
prevChar = char;
|
|
8395
8395
|
}
|
|
8396
8396
|
hasFoldableLine = hasFoldableLine || shouldTrackWidth && (i2 - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " ");
|
|
8397
8397
|
}
|
|
8398
8398
|
if (!hasLineBreak && !hasFoldableLine) {
|
|
8399
|
-
if (
|
|
8399
|
+
if (plain2 && !forceQuotes && !testAmbiguousType(string)) {
|
|
8400
8400
|
return STYLE_PLAIN;
|
|
8401
8401
|
}
|
|
8402
8402
|
return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE;
|
|
@@ -8963,7 +8963,7 @@ import { readFileSync as readFileSync2, readdirSync as readdirSync2, statSync, e
|
|
|
8963
8963
|
import { join as join2, relative } from "node:path";
|
|
8964
8964
|
function scanSource(opts) {
|
|
8965
8965
|
const { db, source, entriesRoot } = opts;
|
|
8966
|
-
const
|
|
8966
|
+
const now2 = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
8967
8967
|
db.exec("DROP TABLE IF EXISTS temp.touched");
|
|
8968
8968
|
db.exec("CREATE TEMP TABLE touched(rowid INTEGER PRIMARY KEY)");
|
|
8969
8969
|
const insertTouched = db.prepare("INSERT INTO touched (rowid) VALUES (?)");
|
|
@@ -8981,7 +8981,7 @@ function scanSource(opts) {
|
|
|
8981
8981
|
path: rel,
|
|
8982
8982
|
content: src,
|
|
8983
8983
|
file_mtime: mtime,
|
|
8984
|
-
indexed_at:
|
|
8984
|
+
indexed_at: now2()
|
|
8985
8985
|
});
|
|
8986
8986
|
const existing = db.prepare("SELECT rowid, file_mtime, path FROM entries WHERE source = ? AND id = ?").get(source, row.id);
|
|
8987
8987
|
if (existing && existing.file_mtime === mtime && existing.path === rel) {
|
|
@@ -9351,7 +9351,7 @@ async function prewarmSealedKeys(opts) {
|
|
|
9351
9351
|
return failures;
|
|
9352
9352
|
}
|
|
9353
9353
|
function scanSealedSource(opts) {
|
|
9354
|
-
const
|
|
9354
|
+
const now2 = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
9355
9355
|
const bundle = readFileSync3(opts.bundlePath);
|
|
9356
9356
|
const { header } = readSealedHeader(bundle);
|
|
9357
9357
|
const contentKey = opts.keyProvider.resolveContentKey(header.keyId, header.keyserverUrl);
|
|
@@ -9370,7 +9370,7 @@ function scanSealedSource(opts) {
|
|
|
9370
9370
|
path: file.relPath,
|
|
9371
9371
|
content: file.content.toString("utf-8"),
|
|
9372
9372
|
file_mtime: bundleMtime,
|
|
9373
|
-
indexed_at:
|
|
9373
|
+
indexed_at: now2()
|
|
9374
9374
|
});
|
|
9375
9375
|
const existing = opts.db.prepare("SELECT rowid FROM entries WHERE source = ? AND id = ?").get(opts.source, row.id);
|
|
9376
9376
|
const rowid = upsertEntry(opts.db, row);
|
|
@@ -9496,9 +9496,9 @@ function acquireFileLock(lockFilePath) {
|
|
|
9496
9496
|
}
|
|
9497
9497
|
return tryCreateLock(lockFilePath) ? { path: lockFilePath } : null;
|
|
9498
9498
|
}
|
|
9499
|
-
function releaseFileLock(
|
|
9499
|
+
function releaseFileLock(lock2) {
|
|
9500
9500
|
try {
|
|
9501
|
-
unlinkSync(
|
|
9501
|
+
unlinkSync(lock2.path);
|
|
9502
9502
|
} catch (err) {
|
|
9503
9503
|
if (err.code !== "ENOENT") throw err;
|
|
9504
9504
|
}
|
|
@@ -9506,8 +9506,8 @@ function releaseFileLock(lock) {
|
|
|
9506
9506
|
function acquireReindexLock(caveatHome) {
|
|
9507
9507
|
return acquireFileLock(lockPath(caveatHome));
|
|
9508
9508
|
}
|
|
9509
|
-
function releaseReindexLock(
|
|
9510
|
-
releaseFileLock(
|
|
9509
|
+
function releaseReindexLock(lock2) {
|
|
9510
|
+
releaseFileLock(lock2);
|
|
9511
9511
|
}
|
|
9512
9512
|
function reindexAllSources(opts) {
|
|
9513
9513
|
const { db, paths, logger, keyProvider } = opts;
|
|
@@ -14800,14 +14800,14 @@ function acquirePendingClaim(caveatHome, sessionId, key, options2 = {}) {
|
|
|
14800
14800
|
const dir = join6(pendingDirFor(caveatHome, sessionId), ".claims");
|
|
14801
14801
|
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
14802
14802
|
const path = join6(dir, `${key}.claim`);
|
|
14803
|
-
const
|
|
14803
|
+
const now2 = options2.now ?? Date.now();
|
|
14804
14804
|
const ttlMs = options2.ttlMs ?? CLAIM_TTL_MS;
|
|
14805
14805
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
14806
14806
|
const ownerToken = randomBytes(16).toString("hex");
|
|
14807
14807
|
try {
|
|
14808
14808
|
const fd = openSync(path, "wx", 384);
|
|
14809
14809
|
try {
|
|
14810
|
-
writeFileSync2(fd, JSON.stringify({ ownerToken, createdAt:
|
|
14810
|
+
writeFileSync2(fd, JSON.stringify({ ownerToken, createdAt: now2 }), "utf-8");
|
|
14811
14811
|
} finally {
|
|
14812
14812
|
closeSync(fd);
|
|
14813
14813
|
}
|
|
@@ -14825,7 +14825,7 @@ function acquirePendingClaim(caveatHome, sessionId, key, options2 = {}) {
|
|
|
14825
14825
|
if (typeof parsed.createdAt === "number") createdAt = parsed.createdAt;
|
|
14826
14826
|
} catch {
|
|
14827
14827
|
}
|
|
14828
|
-
if (
|
|
14828
|
+
if (now2 - createdAt <= ttlMs) return null;
|
|
14829
14829
|
unlinkSync2(path);
|
|
14830
14830
|
} catch (retryError) {
|
|
14831
14831
|
if (retryError && typeof retryError === "object" && retryError.code === "ENOENT") continue;
|
|
@@ -14895,8 +14895,8 @@ function cleanupStalePendingDirs(caveatHome, options2 = {}) {
|
|
|
14895
14895
|
if (staleDays < 0) {
|
|
14896
14896
|
throw new Error(`cleanupStalePendingDirs: staleDays must be >= 0 (got ${staleDays})`);
|
|
14897
14897
|
}
|
|
14898
|
-
const
|
|
14899
|
-
const cutoffMs =
|
|
14898
|
+
const now2 = options2.now ?? /* @__PURE__ */ new Date();
|
|
14899
|
+
const cutoffMs = now2.getTime() - staleDays * 24 * 60 * 60 * 1e3;
|
|
14900
14900
|
const root = join6(caveatHome, "pending");
|
|
14901
14901
|
if (!existsSync6(root)) return { removed: [], kept: 0 };
|
|
14902
14902
|
return withPendingQueueLock(caveatHome, () => {
|
|
@@ -14917,7 +14917,7 @@ function cleanupStalePendingDirs(caveatHome, options2 = {}) {
|
|
|
14917
14917
|
continue;
|
|
14918
14918
|
}
|
|
14919
14919
|
if (!subStat.isDirectory()) continue;
|
|
14920
|
-
if (hasNonExpiredPendingClaim(sub,
|
|
14920
|
+
if (hasNonExpiredPendingClaim(sub, now2.getTime())) {
|
|
14921
14921
|
kept++;
|
|
14922
14922
|
continue;
|
|
14923
14923
|
}
|
|
@@ -14962,19 +14962,19 @@ function maybeSweepPendingDirs(caveatHome, options2 = {}) {
|
|
|
14962
14962
|
`maybeSweepPendingDirs: debounceDays must be >= 0 (got ${debounceDays})`
|
|
14963
14963
|
);
|
|
14964
14964
|
}
|
|
14965
|
-
const
|
|
14965
|
+
const now2 = options2.now ?? /* @__PURE__ */ new Date();
|
|
14966
14966
|
const pendingRoot = join6(caveatHome, "pending");
|
|
14967
14967
|
if (!existsSync6(pendingRoot)) return { skipped: "no_pending_dir" };
|
|
14968
14968
|
const marker = join6(pendingRoot, ".last-sweep");
|
|
14969
14969
|
try {
|
|
14970
14970
|
const m = statSync5(marker);
|
|
14971
|
-
const ageMs =
|
|
14971
|
+
const ageMs = now2.getTime() - m.mtimeMs;
|
|
14972
14972
|
if (ageMs < debounceDays * 24 * 60 * 60 * 1e3) {
|
|
14973
14973
|
return { skipped: "debounced" };
|
|
14974
14974
|
}
|
|
14975
14975
|
} catch {
|
|
14976
14976
|
}
|
|
14977
|
-
const result = cleanupStalePendingDirs(caveatHome, { staleDays, now });
|
|
14977
|
+
const result = cleanupStalePendingDirs(caveatHome, { staleDays, now: now2 });
|
|
14978
14978
|
try {
|
|
14979
14979
|
writeFileSync2(marker, "", "utf-8");
|
|
14980
14980
|
} catch {
|
|
@@ -15434,11 +15434,17 @@ function errorMessage2(err) {
|
|
|
15434
15434
|
}
|
|
15435
15435
|
|
|
15436
15436
|
// ../../packages/core/dist/autoSync.js
|
|
15437
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
15437
15438
|
import { createHash as createHash4 } from "node:crypto";
|
|
15438
|
-
import { mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
15439
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
15439
15440
|
import { dirname as dirname5, join as join9 } from "node:path";
|
|
15440
|
-
var AUTO_SYNC_DEBOUNCE_MS =
|
|
15441
|
+
var AUTO_SYNC_DEBOUNCE_MS = 15 * 60 * 1e3;
|
|
15442
|
+
var AUTO_SYNC_RECORD_DEBOUNCE_MS = 60 * 1e3;
|
|
15443
|
+
var AUTO_SYNC_SUSPEND_THRESHOLD = 3;
|
|
15444
|
+
var AUTO_SYNC_DEGRADED_RETRY_MS = 6 * 60 * 60 * 1e3;
|
|
15445
|
+
var AUTO_SYNC_NOTICE_REPEAT_MS = 24 * 60 * 60 * 1e3;
|
|
15441
15446
|
var CAVEAT_AUTO_SYNC_ENV = "CAVEAT_AUTO_SYNC";
|
|
15447
|
+
var CAVEAT_AUTO_SYNC_DEBOUNCE_ENV = "CAVEAT_AUTO_SYNC_DEBOUNCE_MS";
|
|
15442
15448
|
function syncDir(caveatHome) {
|
|
15443
15449
|
return join9(caveatHome, "sync");
|
|
15444
15450
|
}
|
|
@@ -15471,6 +15477,7 @@ function resetAutoSyncFailureState(caveatHome) {
|
|
|
15471
15477
|
writeAutoSyncState(caveatHome, {
|
|
15472
15478
|
finishedAt: current?.finishedAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
15473
15479
|
signature: current?.signature ?? "",
|
|
15480
|
+
lastNotifiedAt: current?.lastNotifiedAt,
|
|
15474
15481
|
ownSync: { consecutiveFailureSignature: null, consecutiveFailureCount: 0 }
|
|
15475
15482
|
});
|
|
15476
15483
|
} catch {
|
|
@@ -15479,7 +15486,15 @@ function resetAutoSyncFailureState(caveatHome) {
|
|
|
15479
15486
|
function isAutoSyncState(value) {
|
|
15480
15487
|
if (value === null || typeof value !== "object") return false;
|
|
15481
15488
|
const candidate = value;
|
|
15482
|
-
return typeof candidate.finishedAt === "string" && typeof candidate.signature === "string" && candidate.ownSync !== null && typeof candidate.ownSync === "object" && (candidate.ownSync.consecutiveFailureSignature === null || typeof candidate.ownSync.consecutiveFailureSignature === "string") && Number.isInteger(candidate.ownSync.consecutiveFailureCount) && candidate.ownSync.consecutiveFailureCount >= 0;
|
|
15489
|
+
return typeof candidate.finishedAt === "string" && typeof candidate.signature === "string" && isOptionalString(candidate.lastNotifiedAt) && candidate.ownSync !== null && typeof candidate.ownSync === "object" && (candidate.ownSync.consecutiveFailureSignature === null || typeof candidate.ownSync.consecutiveFailureSignature === "string") && Number.isInteger(candidate.ownSync.consecutiveFailureCount) && candidate.ownSync.consecutiveFailureCount >= 0 && isOptionalString(candidate.ownSync.lastAttemptAt);
|
|
15490
|
+
}
|
|
15491
|
+
function isOptionalString(value) {
|
|
15492
|
+
return value === void 0 || typeof value === "string";
|
|
15493
|
+
}
|
|
15494
|
+
function parseTimestamp(value) {
|
|
15495
|
+
if (value === void 0) return 0;
|
|
15496
|
+
const ms = Date.parse(value);
|
|
15497
|
+
return Number.isFinite(ms) ? ms : 0;
|
|
15483
15498
|
}
|
|
15484
15499
|
function classifyOwnSyncOutcome(err, lastProbe) {
|
|
15485
15500
|
if (!(err instanceof SyncError)) return "fail";
|
|
@@ -15507,8 +15522,9 @@ function autoSyncNotification(outcome) {
|
|
|
15507
15522
|
if (outcome.own.pulled === true) {
|
|
15508
15523
|
lines.push("autosync: pulled updates from your private remote");
|
|
15509
15524
|
}
|
|
15510
|
-
|
|
15511
|
-
|
|
15525
|
+
const backoffHours = Math.round(AUTO_SYNC_DEGRADED_RETRY_MS / (60 * 60 * 1e3));
|
|
15526
|
+
if (outcome.own.degraded === true) {
|
|
15527
|
+
lines.push(`autosync: own sync keeps failing; auto-retry is backed off to every ${backoffHours}h. run \`caveat sync\` to resolve now.`);
|
|
15512
15528
|
} else if (outcome.own.disposition === "fail") {
|
|
15513
15529
|
lines.push(`autosync: own sync failed (${outcome.own.code ?? "UNKNOWN"}). run \`caveat sync\` to resolve.`);
|
|
15514
15530
|
}
|
|
@@ -15517,27 +15533,20 @@ function autoSyncNotification(outcome) {
|
|
|
15517
15533
|
lines.push(`autosync: community pull failed: ${failedHandles.join(", ")}`);
|
|
15518
15534
|
}
|
|
15519
15535
|
const text = lines.length > 0 ? lines.join("\n") : null;
|
|
15520
|
-
const signature = sha256(JSON.stringify(
|
|
15521
|
-
lines,
|
|
15522
|
-
own: {
|
|
15523
|
-
disposition: outcome.own.disposition,
|
|
15524
|
-
code: outcome.own.code ?? null,
|
|
15525
|
-
pulled: outcome.own.pulled ?? null,
|
|
15526
|
-
suspended: outcome.own.suspended ?? false,
|
|
15527
|
-
escalated: outcome.own.escalated ?? false
|
|
15528
|
-
},
|
|
15529
|
-
communityFailed: failedHandles
|
|
15530
|
-
}));
|
|
15536
|
+
const signature = sha256(JSON.stringify(lines));
|
|
15531
15537
|
return { signature, text };
|
|
15532
15538
|
}
|
|
15533
15539
|
async function runAutoSync(opts) {
|
|
15534
15540
|
if (process.env[CAVEAT_AUTO_SYNC_ENV] === "off") return { ran: false };
|
|
15535
|
-
const
|
|
15536
|
-
if (!
|
|
15541
|
+
const lock2 = acquireFileLock(autoSyncLockPath(opts.caveatHome));
|
|
15542
|
+
if (!lock2) return { ran: false };
|
|
15537
15543
|
let reindexLock = null;
|
|
15538
15544
|
try {
|
|
15539
15545
|
reindexLock = acquireReindexLock(opts.caveatHome);
|
|
15540
15546
|
if (!reindexLock) return { ran: false };
|
|
15547
|
+
const nowDate = (opts.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
15548
|
+
const nowMs = nowDate.getTime();
|
|
15549
|
+
const nowIso = nowDate.toISOString();
|
|
15541
15550
|
const previousState = readAutoSyncState(opts.caveatHome);
|
|
15542
15551
|
let ownSyncState = previousState?.ownSync ?? {
|
|
15543
15552
|
consecutiveFailureSignature: null,
|
|
@@ -15549,9 +15558,12 @@ async function runAutoSync(opts) {
|
|
|
15549
15558
|
gitTimeoutMs: opts.gitTimeoutMs ?? BACKGROUND_GIT_TIMEOUT_MS
|
|
15550
15559
|
});
|
|
15551
15560
|
let own;
|
|
15552
|
-
|
|
15561
|
+
const degraded = ownSyncState.consecutiveFailureCount >= AUTO_SYNC_SUSPEND_THRESHOLD;
|
|
15562
|
+
const retryDue = nowMs - parseTimestamp(ownSyncState.lastAttemptAt) >= AUTO_SYNC_DEGRADED_RETRY_MS;
|
|
15563
|
+
if (degraded && !retryDue) {
|
|
15553
15564
|
own = { disposition: "skip", suspended: true };
|
|
15554
15565
|
} else {
|
|
15566
|
+
ownSyncState = { ...ownSyncState, lastAttemptAt: nowIso };
|
|
15555
15567
|
let lastProbe;
|
|
15556
15568
|
try {
|
|
15557
15569
|
const result = await syncOwn({
|
|
@@ -15582,23 +15594,27 @@ async function runAutoSync(opts) {
|
|
|
15582
15594
|
const consecutiveFailureCount = ownSyncState.consecutiveFailureSignature === failureSignature ? ownSyncState.consecutiveFailureCount + 1 : 1;
|
|
15583
15595
|
ownSyncState = {
|
|
15584
15596
|
consecutiveFailureSignature: failureSignature,
|
|
15585
|
-
consecutiveFailureCount
|
|
15597
|
+
consecutiveFailureCount,
|
|
15598
|
+
lastAttemptAt: nowIso
|
|
15586
15599
|
};
|
|
15587
|
-
if (consecutiveFailureCount ===
|
|
15600
|
+
if (consecutiveFailureCount === AUTO_SYNC_SUSPEND_THRESHOLD) own.escalated = true;
|
|
15588
15601
|
}
|
|
15589
15602
|
}
|
|
15590
15603
|
}
|
|
15604
|
+
if (ownSyncState.consecutiveFailureCount >= AUTO_SYNC_SUSPEND_THRESHOLD) own.degraded = true;
|
|
15591
15605
|
await reindexAndMark2(opts);
|
|
15592
15606
|
const outcome = { community, own };
|
|
15593
15607
|
const { signature, text } = autoSyncNotification(outcome);
|
|
15608
|
+
const repeatDue = own.degraded === true && nowMs - parseTimestamp(previousState?.lastNotifiedAt) >= AUTO_SYNC_NOTICE_REPEAT_MS;
|
|
15594
15609
|
let notified = false;
|
|
15595
|
-
if (text !== null && previousState?.signature !== signature) {
|
|
15610
|
+
if (text !== null && (previousState?.signature !== signature || repeatDue)) {
|
|
15596
15611
|
appendGlobalPendingReminder(opts.caveatHome, text);
|
|
15597
15612
|
notified = true;
|
|
15598
15613
|
}
|
|
15599
15614
|
writeAutoSyncState(opts.caveatHome, {
|
|
15600
|
-
finishedAt:
|
|
15615
|
+
finishedAt: nowIso,
|
|
15601
15616
|
signature,
|
|
15617
|
+
lastNotifiedAt: notified ? nowIso : previousState?.lastNotifiedAt,
|
|
15602
15618
|
ownSync: ownSyncState
|
|
15603
15619
|
});
|
|
15604
15620
|
return { ran: true, outcome, notified };
|
|
@@ -15614,12 +15630,41 @@ async function runAutoSync(opts) {
|
|
|
15614
15630
|
}
|
|
15615
15631
|
}
|
|
15616
15632
|
try {
|
|
15617
|
-
releaseFileLock(
|
|
15633
|
+
releaseFileLock(lock2);
|
|
15618
15634
|
} catch (err) {
|
|
15619
15635
|
opts.logger.warn(`autosync lock release failed: ${errorMessage3(err)}`);
|
|
15620
15636
|
}
|
|
15621
15637
|
}
|
|
15622
15638
|
}
|
|
15639
|
+
function triggerAutoSync(opts) {
|
|
15640
|
+
if (process.env[CAVEAT_AUTO_SYNC_ENV] === "off") return;
|
|
15641
|
+
const debounceMs = resolveTriggerDebounceMs(opts.debounceMs ?? AUTO_SYNC_DEBOUNCE_MS);
|
|
15642
|
+
const statePath = autoSyncStatePath(opts.caveatHome);
|
|
15643
|
+
try {
|
|
15644
|
+
if (existsSync9(statePath) && Date.now() - statSync6(statePath).mtimeMs < debounceMs) return;
|
|
15645
|
+
} catch {
|
|
15646
|
+
}
|
|
15647
|
+
if (!opts.cliScript) throw new Error("current Caveat CLI script path is unavailable");
|
|
15648
|
+
const child = spawn2(
|
|
15649
|
+
process.execPath,
|
|
15650
|
+
[...process.execArgv, "--disable-warning=ExperimentalWarning", opts.cliScript, "hook", "autosync"],
|
|
15651
|
+
{ detached: true, stdio: "ignore", windowsHide: true }
|
|
15652
|
+
);
|
|
15653
|
+
child.unref();
|
|
15654
|
+
}
|
|
15655
|
+
function resolveTriggerDebounceMs(fallback) {
|
|
15656
|
+
const raw = process.env[CAVEAT_AUTO_SYNC_DEBOUNCE_ENV];
|
|
15657
|
+
if (raw === void 0) return fallback;
|
|
15658
|
+
const parsed = Number(raw);
|
|
15659
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
15660
|
+
process.stderr.write(
|
|
15661
|
+
`[caveat] ${CAVEAT_AUTO_SYNC_DEBOUNCE_ENV}=${raw} is not a non-negative number; using ${fallback}ms
|
|
15662
|
+
`
|
|
15663
|
+
);
|
|
15664
|
+
return fallback;
|
|
15665
|
+
}
|
|
15666
|
+
return parsed;
|
|
15667
|
+
}
|
|
15623
15668
|
async function reindexAndMark2(opts) {
|
|
15624
15669
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: opts.caveatHome });
|
|
15625
15670
|
const failures = await prewarmSealedKeys({ paths: opts.paths, keyProvider });
|
|
@@ -15731,7 +15776,7 @@ function toSearchResult(row) {
|
|
|
15731
15776
|
}
|
|
15732
15777
|
|
|
15733
15778
|
// ../../packages/core/dist/paths.js
|
|
15734
|
-
import { existsSync as
|
|
15779
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
15735
15780
|
import { dirname as dirname6, isAbsolute, join as join10, resolve as resolve2 } from "node:path";
|
|
15736
15781
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15737
15782
|
function expandHome(p2, userHome) {
|
|
@@ -15763,7 +15808,7 @@ function resolvePaths(caveatHome, knowledgeRepo, userHome) {
|
|
|
15763
15808
|
}
|
|
15764
15809
|
|
|
15765
15810
|
// ../../packages/core/dist/config.js
|
|
15766
|
-
import { existsSync as
|
|
15811
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
15767
15812
|
var DEFAULT_CONFIG = {
|
|
15768
15813
|
knowledgeRepo: "own",
|
|
15769
15814
|
semverKeys: ["driver", "cuda", "node"],
|
|
@@ -15772,16 +15817,16 @@ var DEFAULT_CONFIG = {
|
|
|
15772
15817
|
sealedKeyserverUrl: null
|
|
15773
15818
|
};
|
|
15774
15819
|
function loadConfig(userConfigPath) {
|
|
15775
|
-
const userCfg =
|
|
15820
|
+
const userCfg = existsSync11(userConfigPath) ? JSON.parse(readFileSync8(userConfigPath, "utf-8")) : {};
|
|
15776
15821
|
return deepMerge(DEFAULT_CONFIG, userCfg);
|
|
15777
15822
|
}
|
|
15778
15823
|
function ensureUserConfig(userConfigPath) {
|
|
15779
|
-
if (!
|
|
15824
|
+
if (!existsSync11(userConfigPath)) {
|
|
15780
15825
|
writeFileSync6(userConfigPath, "{}\n", "utf-8");
|
|
15781
15826
|
}
|
|
15782
15827
|
}
|
|
15783
15828
|
function writeUserConfigPatch(userConfigPath, patch) {
|
|
15784
|
-
const existing =
|
|
15829
|
+
const existing = existsSync11(userConfigPath) ? JSON.parse(readFileSync8(userConfigPath, "utf-8")) : {};
|
|
15785
15830
|
writeFileSync6(userConfigPath, `${JSON.stringify({ ...existing, ...patch }, null, 2)}
|
|
15786
15831
|
`, "utf-8");
|
|
15787
15832
|
}
|
|
@@ -16090,7 +16135,7 @@ function stopReminderText(signals, related) {
|
|
|
16090
16135
|
}
|
|
16091
16136
|
|
|
16092
16137
|
// ../../packages/core/dist/transcriptSignals.js
|
|
16093
|
-
import { existsSync as
|
|
16138
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
|
|
16094
16139
|
var MAX_ERROR_SNIPPETS = 10;
|
|
16095
16140
|
var MAX_ERROR_SNIPPET_LENGTH = 300;
|
|
16096
16141
|
var MAX_SEARCH_QUERIES = 10;
|
|
@@ -16110,13 +16155,13 @@ function extractResultText(content) {
|
|
|
16110
16155
|
}
|
|
16111
16156
|
return "";
|
|
16112
16157
|
}
|
|
16113
|
-
function
|
|
16158
|
+
function parseTimestamp2(raw) {
|
|
16114
16159
|
if (typeof raw !== "string") return void 0;
|
|
16115
16160
|
const ms = Date.parse(raw);
|
|
16116
16161
|
return Number.isNaN(ms) ? void 0 : ms;
|
|
16117
16162
|
}
|
|
16118
16163
|
function readSessionSignals(transcriptPath) {
|
|
16119
|
-
if (!transcriptPath || !
|
|
16164
|
+
if (!transcriptPath || !existsSync12(transcriptPath)) return null;
|
|
16120
16165
|
let raw;
|
|
16121
16166
|
try {
|
|
16122
16167
|
raw = readFileSync9(transcriptPath, "utf-8");
|
|
@@ -16140,7 +16185,7 @@ function readSessionSignals(transcriptPath) {
|
|
|
16140
16185
|
} catch {
|
|
16141
16186
|
continue;
|
|
16142
16187
|
}
|
|
16143
|
-
const ts =
|
|
16188
|
+
const ts = parseTimestamp2(parsed.timestamp);
|
|
16144
16189
|
if (ts !== void 0) {
|
|
16145
16190
|
if (firstTs === void 0 || ts < firstTs) firstTs = ts;
|
|
16146
16191
|
if (lastTs === void 0 || ts > lastTs) lastTs = ts;
|
|
@@ -16200,7 +16245,7 @@ function struggleSearchText(s) {
|
|
|
16200
16245
|
}
|
|
16201
16246
|
|
|
16202
16247
|
// ../../packages/core/dist/codexTranscriptSignals.js
|
|
16203
|
-
import { existsSync as
|
|
16248
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "node:fs";
|
|
16204
16249
|
var MAX_ERROR_SNIPPETS2 = 10;
|
|
16205
16250
|
var MAX_ERROR_SNIPPET_LENGTH2 = 300;
|
|
16206
16251
|
var MAX_SEARCH_QUERIES2 = 10;
|
|
@@ -16209,7 +16254,7 @@ var MAX_FILE_EDIT_ENTRIES2 = 20;
|
|
|
16209
16254
|
function isRecord2(v) {
|
|
16210
16255
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
16211
16256
|
}
|
|
16212
|
-
function
|
|
16257
|
+
function parseTimestamp3(raw) {
|
|
16213
16258
|
if (typeof raw !== "string") return void 0;
|
|
16214
16259
|
const ms = Date.parse(raw);
|
|
16215
16260
|
return Number.isNaN(ms) ? void 0 : ms;
|
|
@@ -16265,7 +16310,7 @@ function addQuery(searchQueries, query) {
|
|
|
16265
16310
|
searchQueries.push(query.slice(0, MAX_SEARCH_QUERY_LENGTH2));
|
|
16266
16311
|
}
|
|
16267
16312
|
function readCodexSessionSignals(transcriptPath) {
|
|
16268
|
-
if (!transcriptPath || !
|
|
16313
|
+
if (!transcriptPath || !existsSync13(transcriptPath)) return null;
|
|
16269
16314
|
let raw;
|
|
16270
16315
|
try {
|
|
16271
16316
|
raw = readFileSync10(transcriptPath, "utf-8");
|
|
@@ -16291,7 +16336,7 @@ function readCodexSessionSignals(transcriptPath) {
|
|
|
16291
16336
|
} catch {
|
|
16292
16337
|
continue;
|
|
16293
16338
|
}
|
|
16294
|
-
const ts =
|
|
16339
|
+
const ts = parseTimestamp3(parsed.timestamp);
|
|
16295
16340
|
if (ts !== void 0) {
|
|
16296
16341
|
if (firstTs === void 0 || ts < firstTs) firstTs = ts;
|
|
16297
16342
|
if (lastTs === void 0 || ts > lastTs) lastTs = ts;
|
|
@@ -16371,9 +16416,9 @@ function readCodexSessionSignals(transcriptPath) {
|
|
|
16371
16416
|
}
|
|
16372
16417
|
|
|
16373
16418
|
// ../../packages/core/dist/markHit.js
|
|
16374
|
-
function markHit(db, keys,
|
|
16419
|
+
function markHit(db, keys, now2 = () => (/* @__PURE__ */ new Date()).toISOString()) {
|
|
16375
16420
|
if (keys.length === 0) return;
|
|
16376
|
-
const ts =
|
|
16421
|
+
const ts = now2();
|
|
16377
16422
|
const stmt = db.prepare(
|
|
16378
16423
|
"UPDATE entries SET last_hit_at = ? WHERE source = ? AND id = ?"
|
|
16379
16424
|
);
|
|
@@ -16383,7 +16428,7 @@ function markHit(db, keys, now = () => (/* @__PURE__ */ new Date()).toISOString(
|
|
|
16383
16428
|
}
|
|
16384
16429
|
|
|
16385
16430
|
// ../../packages/core/dist/hookQueryLog.js
|
|
16386
|
-
import { appendFileSync, chmodSync as chmodSync2, mkdirSync as mkdirSync7, renameSync as renameSync4, statSync as
|
|
16431
|
+
import { appendFileSync, chmodSync as chmodSync2, mkdirSync as mkdirSync7, renameSync as renameSync4, statSync as statSync7, unlinkSync as unlinkSync3 } from "node:fs";
|
|
16387
16432
|
import { join as join11, resolve as resolve3 } from "node:path";
|
|
16388
16433
|
var CAVEAT_HOOK_QUERY_LOG_ENV = "CAVEAT_HOOK_QUERY_LOG";
|
|
16389
16434
|
var HOOK_QUERY_LOG_MAX_BYTES = 1024 * 1024;
|
|
@@ -16393,7 +16438,7 @@ var fsDependencies = {
|
|
|
16393
16438
|
chmodSync: chmodSync2,
|
|
16394
16439
|
mkdirSync: mkdirSync7,
|
|
16395
16440
|
renameSync: renameSync4,
|
|
16396
|
-
statSync:
|
|
16441
|
+
statSync: statSync7,
|
|
16397
16442
|
unlinkSync: unlinkSync3
|
|
16398
16443
|
};
|
|
16399
16444
|
function isMissingPathError(err) {
|
|
@@ -16453,8 +16498,8 @@ function logHookQueryMiss(miss, dependencies = fsDependencies) {
|
|
|
16453
16498
|
function listStale(db, opts = {}) {
|
|
16454
16499
|
const days = opts.days ?? 90;
|
|
16455
16500
|
const limit = opts.limit ?? 50;
|
|
16456
|
-
const
|
|
16457
|
-
const cutoff = new Date(
|
|
16501
|
+
const now2 = (opts.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
16502
|
+
const cutoff = new Date(now2.getTime() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
16458
16503
|
const conditions = ["(last_hit_at IS NULL OR last_hit_at < ?)"];
|
|
16459
16504
|
const params = [cutoff];
|
|
16460
16505
|
if (opts.visibility === "public" || opts.visibility === "private") {
|
|
@@ -16481,7 +16526,7 @@ function listStale(db, opts = {}) {
|
|
|
16481
16526
|
|
|
16482
16527
|
// ../../packages/core/dist/publishScan.js
|
|
16483
16528
|
import { createHash as createHash5 } from "node:crypto";
|
|
16484
|
-
import { existsSync as
|
|
16529
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
|
|
16485
16530
|
import { join as join12, basename as basename2 } from "node:path";
|
|
16486
16531
|
import { homedir as homedir2, userInfo as userInfo2 } from "node:os";
|
|
16487
16532
|
var ALLOW_FILE = ".caveat-publish-allow.json";
|
|
@@ -16712,7 +16757,7 @@ function publishSelfIdentityTokens() {
|
|
|
16712
16757
|
}
|
|
16713
16758
|
function loadPublishAllow(knowledgeRepo) {
|
|
16714
16759
|
const path = join12(knowledgeRepo, ALLOW_FILE);
|
|
16715
|
-
if (!
|
|
16760
|
+
if (!existsSync14(path)) return /* @__PURE__ */ new Set();
|
|
16716
16761
|
const parsed = JSON.parse(readFileSync11(path, "utf-8"));
|
|
16717
16762
|
if (!Array.isArray(parsed.allow)) throw new Error(`${ALLOW_FILE} must contain an "allow" array`);
|
|
16718
16763
|
return new Set(parsed.allow.filter((value) => typeof value === "string" && DIGEST_RE.test(value)));
|
|
@@ -16742,7 +16787,7 @@ var PublishScanError = class extends Error {
|
|
|
16742
16787
|
|
|
16743
16788
|
// ../../packages/core/dist/publish.js
|
|
16744
16789
|
import { createHash as createHash6 } from "node:crypto";
|
|
16745
|
-
import { existsSync as
|
|
16790
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync12, readdirSync as readdirSync8, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
|
|
16746
16791
|
import { dirname as dirname7, join as join13, relative as relative3 } from "node:path";
|
|
16747
16792
|
|
|
16748
16793
|
// ../../packages/core/dist/visibility.js
|
|
@@ -16758,7 +16803,7 @@ var TMP_BRANCH = "caveat-publish-tmp";
|
|
|
16758
16803
|
function collectPublishSet(entriesDir) {
|
|
16759
16804
|
const files = [];
|
|
16760
16805
|
const invalid = [];
|
|
16761
|
-
if (!
|
|
16806
|
+
if (!existsSync15(entriesDir)) return { files, invalid };
|
|
16762
16807
|
for (const path of walkMarkdown(entriesDir)) {
|
|
16763
16808
|
const relPath = relative3(entriesDir, path).replace(/\\/g, "/");
|
|
16764
16809
|
const content = readFileSync12(path);
|
|
@@ -16779,7 +16824,7 @@ function collectPublishSet(entriesDir) {
|
|
|
16779
16824
|
}
|
|
16780
16825
|
async function preparePublishMirror(opts) {
|
|
16781
16826
|
const git = opts.git ?? createGit();
|
|
16782
|
-
if (!
|
|
16827
|
+
if (!existsSync15(opts.mirrorDir)) {
|
|
16783
16828
|
mkdirSync8(dirname7(opts.mirrorDir), { recursive: true });
|
|
16784
16829
|
await git.clone(opts.target, opts.mirrorDir);
|
|
16785
16830
|
} else {
|
|
@@ -16952,8 +16997,8 @@ function readExistingMirror(mirrorDir) {
|
|
|
16952
16997
|
const readmePath = join13(mirrorDir, "README.md");
|
|
16953
16998
|
const bundlePath = join13(mirrorDir, BUNDLE_RELPATH);
|
|
16954
16999
|
return {
|
|
16955
|
-
readme:
|
|
16956
|
-
bundle:
|
|
17000
|
+
readme: existsSync15(readmePath) ? readFileSync12(readmePath, "utf-8") : null,
|
|
17001
|
+
bundle: existsSync15(bundlePath) ? readFileSync12(bundlePath) : null
|
|
16957
17002
|
};
|
|
16958
17003
|
}
|
|
16959
17004
|
async function publishOwn(opts) {
|
|
@@ -17241,9 +17286,323 @@ function boundedCount(value) {
|
|
|
17241
17286
|
return Math.min(1e4, Math.max(0, Math.floor(value)));
|
|
17242
17287
|
}
|
|
17243
17288
|
|
|
17289
|
+
// ../../packages/core/dist/runtimeErrors.js
|
|
17290
|
+
import { spawnSync } from "node:child_process";
|
|
17291
|
+
import { createHash as createHash7, randomBytes as randomBytes3 } from "node:crypto";
|
|
17292
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync16, fstatSync, lstatSync, mkdirSync as mkdirSync9, openSync as openSync2, readFileSync as readFileSync13, renameSync as renameSync5, rmSync as rmSync6, statSync as statSync8, writeFileSync as writeFileSync9 } from "node:fs";
|
|
17293
|
+
import { arch as hostArch, homedir as homedir3, platform as hostPlatform } from "node:os";
|
|
17294
|
+
import { dirname as dirname8, join as join14 } from "node:path";
|
|
17295
|
+
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
17296
|
+
var RUNTIME_ERRORS_SCHEMA = "caveat.runtime_errors.v1";
|
|
17297
|
+
var STATE_VERSION = "1.0";
|
|
17298
|
+
var MAX_RECORDS = 256;
|
|
17299
|
+
var RETENTION_MS = 30 * 864e5;
|
|
17300
|
+
var MAX_CONFIG_BYTES = 64 * 1024;
|
|
17301
|
+
var definitions = {
|
|
17302
|
+
"CAVEAT.DATABASE_OPEN_FAILED": { component: "database", severity: "high", template: "Caveat database open failed" },
|
|
17303
|
+
"CAVEAT.INDEX_FAILED": { component: "index", severity: "high", template: "Caveat index operation failed" },
|
|
17304
|
+
"CAVEAT.SYNC_FAILED": { component: "sync", severity: "high", template: "Caveat own sync failed" },
|
|
17305
|
+
"CAVEAT.MCP_SERVER_FAILED": { component: "mcp", severity: "high", template: "Caveat MCP server failed" },
|
|
17306
|
+
"CAVEAT.MCP_TOOL_FAILED": { component: "mcp_tool", severity: "high", template: "Caveat MCP tool handler failed" },
|
|
17307
|
+
"CAVEAT.CLAUDE_HOOK_FAILED": { component: "claude_hook", severity: "high", template: "Caveat Claude hook failed" },
|
|
17308
|
+
"CAVEAT.CODEX_HOOK_FAILED": { component: "codex_hook", severity: "high", template: "Caveat Codex hook failed" }
|
|
17309
|
+
};
|
|
17310
|
+
function normalizeOptions(options2 = {}) {
|
|
17311
|
+
return "env" in options2 || "configPath" in options2 || "storePath" in options2 || "version" in options2 || "isWindows" in options2 ? options2 : { env: options2 };
|
|
17312
|
+
}
|
|
17313
|
+
var plain = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17314
|
+
var exact = (v, keys) => Object.keys(v).length === keys.length && keys.every((key) => Object.hasOwn(v, key));
|
|
17315
|
+
var validTime = (v) => typeof v === "string" && Number.isFinite(Date.parse(v)) && new Date(v).toISOString() === v;
|
|
17316
|
+
var validVersion = (v) => typeof v === "string" && /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(v);
|
|
17317
|
+
var validOs = (v) => typeof v === "string" && ["darwin", "linux", "windows"].includes(v);
|
|
17318
|
+
var validArch = (v) => typeof v === "string" && ["x64", "arm64", "arm", "ia32"].includes(v);
|
|
17319
|
+
var windows = (env) => env.OS === "Windows_NT" || hostPlatform() === "win32";
|
|
17320
|
+
function defaultFactoryReporterConfigPath(env = process.env) {
|
|
17321
|
+
const home = env.HOME || env.USERPROFILE || homedir3();
|
|
17322
|
+
return windows(env) ? join14(env.LOCALAPPDATA || join14(home, "AppData", "Local"), "dotagents", "factory-reporter", "config.json") : join14(env.XDG_CONFIG_HOME || join14(home, ".config"), "dotagents", "factory-reporter.json");
|
|
17323
|
+
}
|
|
17324
|
+
function runtimeErrorsStatePath(env = process.env) {
|
|
17325
|
+
const home = env.HOME || env.USERPROFILE || homedir3();
|
|
17326
|
+
return windows(env) ? join14(env.LOCALAPPDATA || join14(home, "AppData", "Local"), "caveat", "runtime-errors.json") : join14(env.XDG_STATE_HOME || join14(home, ".local", "state"), "caveat", "runtime-errors.json");
|
|
17327
|
+
}
|
|
17328
|
+
function collectionEnabled(options2 = {}) {
|
|
17329
|
+
const env = options2.env ?? process.env;
|
|
17330
|
+
try {
|
|
17331
|
+
const path = options2.configPath ?? defaultFactoryReporterConfigPath(env);
|
|
17332
|
+
const isWin = (options2.isWindows ?? windows)(env);
|
|
17333
|
+
const before = lstatSync(path);
|
|
17334
|
+
if (!before.isFile() || before.isSymbolicLink() || before.size > MAX_CONFIG_BYTES) return false;
|
|
17335
|
+
if (isWin) secureWindowsAcl(path, options2.aclRunner);
|
|
17336
|
+
else assertPosix(before, 384);
|
|
17337
|
+
const fd = openSync2(path, constants.O_RDONLY | constants.O_NONBLOCK | (constants.O_NOFOLLOW ?? 0));
|
|
17338
|
+
let text;
|
|
17339
|
+
try {
|
|
17340
|
+
const after = fstatSync(fd);
|
|
17341
|
+
if (before.dev !== after.dev || before.ino !== after.ino || after.size > MAX_CONFIG_BYTES) return false;
|
|
17342
|
+
if (!isWin) assertPosix(after, 384);
|
|
17343
|
+
text = readFileSync13(fd, "utf8");
|
|
17344
|
+
} finally {
|
|
17345
|
+
closeSync2(fd);
|
|
17346
|
+
}
|
|
17347
|
+
const config = JSON.parse(text);
|
|
17348
|
+
return plain(config) && exact(config, ["schema_version", "host", "collection", "reporting"]) && config.schema_version === "1.0" && plain(config.host) && exact(config.host, ["id", "profile"]) && typeof config.host.id === "string" && /^[a-z0-9][a-z0-9._-]{0,63}$/.test(config.host.id) && ["server", "mac", "wsl", "windows-native"].includes(config.host.profile) && plain(config.collection) && exact(config.collection, ["enabled"]) && config.collection.enabled === true && canonicalReporting(config.reporting);
|
|
17349
|
+
} catch {
|
|
17350
|
+
return false;
|
|
17351
|
+
}
|
|
17352
|
+
}
|
|
17353
|
+
var empty = () => ({ schema: RUNTIME_ERRORS_SCHEMA, next_sequence: 1, acknowledged_through: 0, records: [] });
|
|
17354
|
+
function fingerprint(code) {
|
|
17355
|
+
const d = definitions[code];
|
|
17356
|
+
return createHash7("sha256").update(`caveat\0${d.component}\0${code}\0${d.template}`).digest("hex");
|
|
17357
|
+
}
|
|
17358
|
+
function ensureSafeDir(dir, isWin, options2 = {}) {
|
|
17359
|
+
const existed = existsSync16(dir);
|
|
17360
|
+
mkdirSync9(dir, { recursive: true, mode: 448 });
|
|
17361
|
+
const s = lstatSync(dir);
|
|
17362
|
+
if (!s.isDirectory() || s.isSymbolicLink()) throw Error("store_unsafe");
|
|
17363
|
+
if (isWin) secureWindowsAcl(dir, options2.aclRunner, true, !existed);
|
|
17364
|
+
else assertPosix(s, 448);
|
|
17365
|
+
}
|
|
17366
|
+
function canonicalReporting(value) {
|
|
17367
|
+
if (!plain(value) || !Object.keys(value).every((key) => ["enabled", "endpoint", "credential_file"].includes(key)) || typeof value.enabled !== "boolean") return false;
|
|
17368
|
+
if (value.endpoint !== void 0) {
|
|
17369
|
+
if (typeof value.endpoint !== "string" || value.endpoint.length > 2048) return false;
|
|
17370
|
+
try {
|
|
17371
|
+
if (!["http:", "https:"].includes(new URL(value.endpoint).protocol)) return false;
|
|
17372
|
+
} catch {
|
|
17373
|
+
return false;
|
|
17374
|
+
}
|
|
17375
|
+
}
|
|
17376
|
+
if (value.credential_file !== void 0 && (typeof value.credential_file !== "string" || value.credential_file.length < 1 || value.credential_file.length > 4096)) return false;
|
|
17377
|
+
return !value.enabled || value.endpoint !== void 0 && value.credential_file !== void 0;
|
|
17378
|
+
}
|
|
17379
|
+
var WINDOWS_ACL_VERIFY = String.raw`$p=$env:CAVEAT_ACL_PATH;$isDir=$env:CAVEAT_ACL_DIRECTORY -eq '1';$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value;$acl=if($isDir){[System.IO.Directory]::GetAccessControl($p)}else{[System.IO.File]::GetAccessControl($p)};$owner=$acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value;if($owner -ne $sid){exit 41};$rules=@($acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier]));if($rules.Count -ne 1){exit 42};$r=$rules[0];if($r.IdentityReference.Value -ne $sid -or $r.AccessControlType -ne 'Allow' -or $r.IsInherited -or ($r.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl){exit 43}`;
|
|
17380
|
+
var WINDOWS_ACL_APPLY = String.raw`$p=$env:CAVEAT_ACL_PATH;$isDir=$env:CAVEAT_ACL_DIRECTORY -eq '1';$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User;$acl=if($isDir){New-Object System.Security.AccessControl.DirectorySecurity}else{New-Object System.Security.AccessControl.FileSecurity};$acl.SetAccessRuleProtection($true,$false);$flags=if($isDir){[System.Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'}else{[System.Security.AccessControl.InheritanceFlags]::None};$rule=New-Object System.Security.AccessControl.FileSystemAccessRule($sid,'FullControl',$flags,[System.Security.AccessControl.PropagationFlags]::None,[System.Security.AccessControl.AccessControlType]::Allow);$acl.SetOwner($sid);$acl.AddAccessRule($rule);if($isDir){[System.IO.Directory]::SetAccessControl($p,$acl)}else{[System.IO.File]::SetAccessControl($p,$acl)};` + WINDOWS_ACL_VERIFY;
|
|
17381
|
+
var WINDOWS_ACL_TIMEOUT_MS = 15e3;
|
|
17382
|
+
function runWindowsAcl(path, directory, apply) {
|
|
17383
|
+
const result = spawnSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", apply ? WINDOWS_ACL_APPLY : WINDOWS_ACL_VERIFY], { env: { ...process.env, CAVEAT_ACL_PATH: path, CAVEAT_ACL_DIRECTORY: directory ? "1" : "0" }, encoding: "utf-8", timeout: WINDOWS_ACL_TIMEOUT_MS, windowsHide: true });
|
|
17384
|
+
if (result.error !== void 0) throw Error(`store_unsafe: powershell spawn ${result.error.code ?? result.error.message}`);
|
|
17385
|
+
if (result.status !== 0) throw Error(`store_unsafe: powershell exit=${result.status} signal=${result.signal ?? "none"} stderr=${(result.stderr ?? "").replace(/\s+/g, " ").trim().slice(0, 400) || "(empty)"}`);
|
|
17386
|
+
}
|
|
17387
|
+
function secureWindowsAcl(path, runner, directory = false, apply = false) {
|
|
17388
|
+
try {
|
|
17389
|
+
(runner ?? runWindowsAcl)(path, directory, apply);
|
|
17390
|
+
} catch {
|
|
17391
|
+
throw Error("store_unsafe");
|
|
17392
|
+
}
|
|
17393
|
+
}
|
|
17394
|
+
function assertPosix(info, mode) {
|
|
17395
|
+
if ((info.mode & 511) !== mode || typeof process.getuid === "function" && info.uid !== process.getuid()) throw Error("store_unsafe");
|
|
17396
|
+
}
|
|
17397
|
+
function ensureSafeFile(path, isWin, options2 = {}) {
|
|
17398
|
+
const s = lstatSync(path);
|
|
17399
|
+
if (!s.isFile() || s.isSymbolicLink()) throw Error("store_unsafe");
|
|
17400
|
+
if (isWin) secureWindowsAcl(path, options2.aclRunner);
|
|
17401
|
+
else assertPosix(statSync8(path), 384);
|
|
17402
|
+
}
|
|
17403
|
+
function validate(store) {
|
|
17404
|
+
if (!plain(store) || !exact(store, ["schema", "next_sequence", "acknowledged_through", "records"])) throw Error("state_invalid");
|
|
17405
|
+
const checked = store;
|
|
17406
|
+
if (checked.schema !== RUNTIME_ERRORS_SCHEMA || !Number.isSafeInteger(checked.next_sequence) || checked.next_sequence < 1 || !Number.isSafeInteger(checked.acknowledged_through) || checked.acknowledged_through < 0 || checked.acknowledged_through >= checked.next_sequence || !Array.isArray(checked.records) || checked.records.length > MAX_RECORDS) throw Error("state_invalid");
|
|
17407
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17408
|
+
let previous = 0;
|
|
17409
|
+
for (const record of checked.records) {
|
|
17410
|
+
if (!plain(record) || !exact(record, ["product", "product_version", "component", "error_code", "message_template", "severity", "fingerprint", "count", "first_seen", "last_seen", "state_schema_version", "os", "arch", "status", "resolved_at", "reason_code", "sequence"])) throw Error("state_invalid");
|
|
17411
|
+
const code = typeof record.error_code === "string" ? record.error_code : void 0;
|
|
17412
|
+
const d = code && definitions[code];
|
|
17413
|
+
if (!d || record.product !== "caveat" || !validVersion(record.product_version) || record.component !== d.component || record.message_template !== d.template || record.severity !== d.severity || record.fingerprint !== fingerprint(code) || seen.has(record.fingerprint) || !Number.isSafeInteger(record.count) || record.count < 1 || !validTime(record.first_seen) || !validTime(record.last_seen) || Date.parse(record.first_seen) > Date.parse(record.last_seen) || record.state_schema_version !== STATE_VERSION || !validOs(record.os) || !validArch(record.arch) || !Number.isSafeInteger(record.sequence) || record.sequence <= previous || record.sequence >= checked.next_sequence || !["open", "resolved"].includes(record.status) || record.status === "open" && (record.resolved_at !== null || record.reason_code !== null) || record.status === "resolved" && (typeof record.resolved_at !== "string" || !validTime(record.resolved_at) || Date.parse(record.resolved_at) < Date.parse(record.last_seen) || record.reason_code !== "operator_resolved")) throw Error("state_invalid");
|
|
17414
|
+
seen.add(record.fingerprint);
|
|
17415
|
+
previous = record.sequence;
|
|
17416
|
+
}
|
|
17417
|
+
}
|
|
17418
|
+
function readStore(path, isWin, options2 = {}) {
|
|
17419
|
+
if (!existsSync16(path)) return empty();
|
|
17420
|
+
ensureSafeFile(path, isWin, options2);
|
|
17421
|
+
const value = JSON.parse(readFileSync13(path, "utf8"));
|
|
17422
|
+
validate(value);
|
|
17423
|
+
return value;
|
|
17424
|
+
}
|
|
17425
|
+
function lock(path, isWin, fn, options2 = {}) {
|
|
17426
|
+
ensureSafeDir(dirname8(path), isWin, options2);
|
|
17427
|
+
const lockPath2 = `${path}.lock.sqlite`;
|
|
17428
|
+
let created = false;
|
|
17429
|
+
try {
|
|
17430
|
+
writeFileSync9(lockPath2, "", { mode: 384, flag: "wx" });
|
|
17431
|
+
created = true;
|
|
17432
|
+
} catch (error) {
|
|
17433
|
+
if (!plain(error) || error.code !== "EEXIST") throw error;
|
|
17434
|
+
}
|
|
17435
|
+
if (created) {
|
|
17436
|
+
if (isWin) secureWindowsAcl(lockPath2, options2.aclRunner, false, true);
|
|
17437
|
+
else assertPosix(statSync8(lockPath2), 384);
|
|
17438
|
+
} else ensureSafeFile(lockPath2, isWin, options2);
|
|
17439
|
+
const db = new DatabaseSync3(lockPath2);
|
|
17440
|
+
let begun = false;
|
|
17441
|
+
try {
|
|
17442
|
+
ensureSafeFile(lockPath2, isWin, options2);
|
|
17443
|
+
db.exec("PRAGMA busy_timeout=5000; PRAGMA synchronous=FULL; BEGIN IMMEDIATE");
|
|
17444
|
+
begun = true;
|
|
17445
|
+
const result = fn();
|
|
17446
|
+
db.exec("COMMIT");
|
|
17447
|
+
begun = false;
|
|
17448
|
+
return result;
|
|
17449
|
+
} finally {
|
|
17450
|
+
if (begun) try {
|
|
17451
|
+
db.exec("ROLLBACK");
|
|
17452
|
+
} catch {
|
|
17453
|
+
}
|
|
17454
|
+
db.close();
|
|
17455
|
+
}
|
|
17456
|
+
}
|
|
17457
|
+
function writeStore(path, store, isWin, options2 = {}) {
|
|
17458
|
+
validate(store);
|
|
17459
|
+
ensureSafeDir(dirname8(path), isWin, options2);
|
|
17460
|
+
const temporary = join14(dirname8(path), `.runtime-errors-${process.pid}-${randomBytes3(6).toString("hex")}`);
|
|
17461
|
+
try {
|
|
17462
|
+
writeFileSync9(temporary, `${JSON.stringify(store)}
|
|
17463
|
+
`, { mode: 384, flag: "wx" });
|
|
17464
|
+
if (isWin) secureWindowsAcl(temporary, options2.aclRunner, false, true);
|
|
17465
|
+
else assertPosix(statSync8(temporary), 384);
|
|
17466
|
+
renameSync5(temporary, path);
|
|
17467
|
+
ensureSafeFile(path, isWin, options2);
|
|
17468
|
+
} finally {
|
|
17469
|
+
rmSync6(temporary, { force: true });
|
|
17470
|
+
}
|
|
17471
|
+
}
|
|
17472
|
+
function now(options2) {
|
|
17473
|
+
const value = options2.now ? new Date(options2.now) : /* @__PURE__ */ new Date();
|
|
17474
|
+
if (Number.isNaN(value.valueOf())) throw Error("invalid_time");
|
|
17475
|
+
return value.toISOString();
|
|
17476
|
+
}
|
|
17477
|
+
function normalizeOs(value) {
|
|
17478
|
+
return value === "win32" ? "windows" : value;
|
|
17479
|
+
}
|
|
17480
|
+
function optionsFor(options2) {
|
|
17481
|
+
const env = options2.env ?? process.env;
|
|
17482
|
+
const isWin = (options2.isWindows ?? windows)(env);
|
|
17483
|
+
return { env, isWin, path: options2.storePath ?? runtimeErrorsStatePath(env) };
|
|
17484
|
+
}
|
|
17485
|
+
function requireCursor(value) {
|
|
17486
|
+
if (!Number.isSafeInteger(value) || value < 0) throw Error("invalid_cursor");
|
|
17487
|
+
}
|
|
17488
|
+
function requireLimit(value) {
|
|
17489
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_RECORDS) throw Error("invalid_limit");
|
|
17490
|
+
}
|
|
17491
|
+
function snapshot(options2 = {}) {
|
|
17492
|
+
const afterCursor = options2.afterCursor ?? 0, limit = options2.limit ?? MAX_RECORDS;
|
|
17493
|
+
requireCursor(afterCursor);
|
|
17494
|
+
requireLimit(limit);
|
|
17495
|
+
const enabled = collectionEnabled(options2);
|
|
17496
|
+
const { path, isWin } = optionsFor(options2);
|
|
17497
|
+
const store = enabled ? readStore(path, isWin, options2) : empty();
|
|
17498
|
+
if (afterCursor > store.next_sequence - 1) throw Error("invalid_cursor");
|
|
17499
|
+
const all = store.records.filter((r2) => r2.sequence > afterCursor);
|
|
17500
|
+
const rows = all.slice(0, limit);
|
|
17501
|
+
return { schema: RUNTIME_ERRORS_SCHEMA, product: "caveat", version: options2.version ?? "unknown", state_schema_version: STATE_VERSION, cursor: { high_watermark: store.next_sequence - 1, acknowledged_through: store.acknowledged_through, next: rows.at(-1)?.sequence ?? afterCursor }, runtime_errors: rows.filter((r2) => r2.status === "open").map(({ error_code, component, status, severity, fingerprint: fingerprint22, message_template, count, first_seen, last_seen, state_schema_version }) => ({ error_code, component, status, severity, fingerprint: fingerprint22, message_template, occurrence_count: count, first_seen, last_seen, state_schema_version })), resolutions: rows.filter((r2) => r2.status === "resolved").map(({ fingerprint: fingerprint22, resolved_at, reason_code }) => ({ fingerprint: fingerprint22, resolved_at, reason_code })), diagnostics: { collection: enabled ? "enabled" : "disabled", status: enabled ? "ready" : "not_applicable", total_count: store.records.length, pending_count: store.records.filter((r2) => r2.sequence > store.acknowledged_through).length, truncated: all.length > rows.length } };
|
|
17502
|
+
}
|
|
17503
|
+
function runtimeErrorsDiagnostics(options2 = {}) {
|
|
17504
|
+
if (!collectionEnabled(options2)) return { schema: "caveat.runtime_error_diagnostics.v1", collection: "disabled", status: "not_applicable", total_count: 0, open_count: 0, pending_count: 0, high_watermark: 0, acknowledged_through: 0 };
|
|
17505
|
+
try {
|
|
17506
|
+
const { path, isWin } = optionsFor(options2);
|
|
17507
|
+
const store = readStore(path, isWin, options2);
|
|
17508
|
+
return { schema: "caveat.runtime_error_diagnostics.v1", collection: "enabled", status: "ready", total_count: store.records.length, open_count: store.records.filter((record) => record.status === "open").length, pending_count: store.records.filter((record) => record.sequence > store.acknowledged_through).length, high_watermark: store.next_sequence - 1, acknowledged_through: store.acknowledged_through };
|
|
17509
|
+
} catch {
|
|
17510
|
+
return { schema: "caveat.runtime_error_diagnostics.v1", collection: "enabled", status: "unavailable", total_count: 0, open_count: 0, pending_count: 0, high_watermark: 0, acknowledged_through: 0 };
|
|
17511
|
+
}
|
|
17512
|
+
}
|
|
17513
|
+
function recordRuntimeError(code, options2 = {}) {
|
|
17514
|
+
if (!collectionEnabled(options2)) return { status: "disabled" };
|
|
17515
|
+
const { path, isWin } = optionsFor(options2);
|
|
17516
|
+
return lock(path, isWin, () => {
|
|
17517
|
+
const store = readStore(path, isWin, options2);
|
|
17518
|
+
const definition = definitions[code];
|
|
17519
|
+
if (!definition) throw Error("unknown_runtime_code");
|
|
17520
|
+
const key = fingerprint(code);
|
|
17521
|
+
const sequence = store.next_sequence++;
|
|
17522
|
+
const time = now(options2);
|
|
17523
|
+
const existing = store.records.find((r2) => r2.fingerprint === key);
|
|
17524
|
+
const version = options2.version ?? "0.0.0";
|
|
17525
|
+
const os = normalizeOs(options2.os ?? hostPlatform());
|
|
17526
|
+
const arch = options2.arch ?? hostArch();
|
|
17527
|
+
if (!validVersion(version) || !validOs(os) || !validArch(arch)) throw Error("invalid_runtime_metadata");
|
|
17528
|
+
if (existing) {
|
|
17529
|
+
existing.product_version = version;
|
|
17530
|
+
existing.os = os;
|
|
17531
|
+
existing.arch = arch;
|
|
17532
|
+
existing.count += 1;
|
|
17533
|
+
existing.last_seen = time;
|
|
17534
|
+
existing.sequence = sequence;
|
|
17535
|
+
existing.status = "open";
|
|
17536
|
+
existing.resolved_at = null;
|
|
17537
|
+
existing.reason_code = null;
|
|
17538
|
+
} else {
|
|
17539
|
+
if (store.records.length >= MAX_RECORDS) throw Error("store_overflow");
|
|
17540
|
+
store.records.push({ product: "caveat", product_version: version, component: definition.component, error_code: code, message_template: definition.template, severity: definition.severity, fingerprint: key, count: 1, first_seen: time, last_seen: time, state_schema_version: STATE_VERSION, os, arch, status: "open", resolved_at: null, reason_code: null, sequence });
|
|
17541
|
+
}
|
|
17542
|
+
store.records.sort((a, b2) => a.sequence - b2.sequence);
|
|
17543
|
+
writeStore(path, store, isWin, options2);
|
|
17544
|
+
return { status: "recorded", fingerprint: key, sequence };
|
|
17545
|
+
}, options2);
|
|
17546
|
+
}
|
|
17547
|
+
function observeRuntimeError(code, options2 = {}) {
|
|
17548
|
+
try {
|
|
17549
|
+
recordRuntimeError(code, options2);
|
|
17550
|
+
} catch {
|
|
17551
|
+
try {
|
|
17552
|
+
process.stderr.write("[caveat:runtime-errors] store_unavailable\n");
|
|
17553
|
+
} catch {
|
|
17554
|
+
}
|
|
17555
|
+
}
|
|
17556
|
+
}
|
|
17557
|
+
var runtimeErrorsSnapshot = (afterCursor = 0, limit = MAX_RECORDS, options2 = {}) => snapshot({ ...normalizeOptions(options2), afterCursor, limit });
|
|
17558
|
+
function acknowledgeRuntimeErrors(cursor, options2 = {}) {
|
|
17559
|
+
const normalized = normalizeOptions(options2);
|
|
17560
|
+
requireCursor(cursor);
|
|
17561
|
+
if (!collectionEnabled(normalized)) return snapshot({ ...normalized, afterCursor: cursor });
|
|
17562
|
+
const { path, isWin } = optionsFor(normalized);
|
|
17563
|
+
lock(path, isWin, () => {
|
|
17564
|
+
const store = readStore(path, isWin, normalized);
|
|
17565
|
+
if (cursor >= store.next_sequence) throw Error("invalid_cursor");
|
|
17566
|
+
store.acknowledged_through = Math.max(store.acknowledged_through, cursor);
|
|
17567
|
+
writeStore(path, store, isWin, normalized);
|
|
17568
|
+
}, normalized);
|
|
17569
|
+
return snapshot(normalized);
|
|
17570
|
+
}
|
|
17571
|
+
function setRuntimeErrorStatus(fingerprintValue, status, options2 = {}) {
|
|
17572
|
+
const normalized = normalizeOptions(options2);
|
|
17573
|
+
if (!/^[0-9a-f]{64}$/.test(fingerprintValue)) throw Error("invalid_fingerprint");
|
|
17574
|
+
if (!collectionEnabled(normalized)) return snapshot(normalized);
|
|
17575
|
+
const { path, isWin } = optionsFor(normalized);
|
|
17576
|
+
lock(path, isWin, () => {
|
|
17577
|
+
const store = readStore(path, isWin, normalized);
|
|
17578
|
+
const record = store.records.find((r2) => r2.fingerprint === fingerprintValue);
|
|
17579
|
+
if (!record) throw Error("fingerprint_not_found");
|
|
17580
|
+
if (record.status === status) return;
|
|
17581
|
+
record.status = status;
|
|
17582
|
+
record.resolved_at = status === "resolved" ? now(normalized) : null;
|
|
17583
|
+
record.reason_code = status === "resolved" ? "operator_resolved" : null;
|
|
17584
|
+
record.sequence = store.next_sequence++;
|
|
17585
|
+
store.records.sort((a, b2) => a.sequence - b2.sequence);
|
|
17586
|
+
writeStore(path, store, isWin, normalized);
|
|
17587
|
+
}, normalized);
|
|
17588
|
+
return snapshot(normalized);
|
|
17589
|
+
}
|
|
17590
|
+
function compactRuntimeErrors(options2 = {}) {
|
|
17591
|
+
const normalized = normalizeOptions(options2);
|
|
17592
|
+
if (!collectionEnabled(normalized)) return snapshot(normalized);
|
|
17593
|
+
const { path, isWin } = optionsFor(normalized);
|
|
17594
|
+
lock(path, isWin, () => {
|
|
17595
|
+
const store = readStore(path, isWin, normalized);
|
|
17596
|
+
const cutoff = Date.parse(now(normalized)) - RETENTION_MS;
|
|
17597
|
+
store.records = store.records.filter((record) => !(record.status === "resolved" && record.sequence <= store.acknowledged_through && record.resolved_at !== null && Date.parse(record.resolved_at) <= cutoff));
|
|
17598
|
+
writeStore(path, store, isWin, normalized);
|
|
17599
|
+
}, normalized);
|
|
17600
|
+
return snapshot(normalized);
|
|
17601
|
+
}
|
|
17602
|
+
|
|
17244
17603
|
// ../../packages/core/dist/env.js
|
|
17245
17604
|
var import_semver = __toESM(require_semver2(), 1);
|
|
17246
|
-
function
|
|
17605
|
+
function fingerprint2() {
|
|
17247
17606
|
return {
|
|
17248
17607
|
os: process.platform,
|
|
17249
17608
|
arch: process.arch,
|
|
@@ -17252,16 +17611,16 @@ function fingerprint() {
|
|
|
17252
17611
|
}
|
|
17253
17612
|
|
|
17254
17613
|
// ../../packages/core/dist/id.js
|
|
17255
|
-
import { randomBytes as
|
|
17614
|
+
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
17256
17615
|
function randomHex(hexChars) {
|
|
17257
17616
|
const bytes = Math.ceil(hexChars / 2);
|
|
17258
|
-
return
|
|
17617
|
+
return randomBytes4(bytes).toString("hex").slice(0, hexChars);
|
|
17259
17618
|
}
|
|
17260
|
-
function slugify(title,
|
|
17619
|
+
function slugify(title, now2 = () => /* @__PURE__ */ new Date()) {
|
|
17261
17620
|
const lowered = title.toLowerCase();
|
|
17262
17621
|
const sluggy = lowered.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
17263
17622
|
if (!sluggy || !/^[a-z0-9]/.test(sluggy)) {
|
|
17264
|
-
const d =
|
|
17623
|
+
const d = now2();
|
|
17265
17624
|
const yyyy = d.getUTCFullYear().toString().padStart(4, "0");
|
|
17266
17625
|
const mm = (d.getUTCMonth() + 1).toString().padStart(2, "0");
|
|
17267
17626
|
const dd = d.getUTCDate().toString().padStart(2, "0");
|
|
@@ -17275,13 +17634,13 @@ function resolveCollision(baseId, exists2) {
|
|
|
17275
17634
|
while (exists2(`${baseId}-${n}`)) n++;
|
|
17276
17635
|
return `${baseId}-${n}`;
|
|
17277
17636
|
}
|
|
17278
|
-
function generateSourceSession(
|
|
17279
|
-
return `${
|
|
17637
|
+
function generateSourceSession(now2 = () => /* @__PURE__ */ new Date()) {
|
|
17638
|
+
return `${now2().toISOString()}/${randomHex(12)}`;
|
|
17280
17639
|
}
|
|
17281
17640
|
|
|
17282
17641
|
// ../../packages/core/dist/writer.js
|
|
17283
|
-
import { existsSync as
|
|
17284
|
-
import { dirname as
|
|
17642
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
17643
|
+
import { dirname as dirname9 } from "node:path";
|
|
17285
17644
|
function buildEntry(frontmatter, sections) {
|
|
17286
17645
|
const bodyParts = [];
|
|
17287
17646
|
for (const [heading, content2] of Object.entries(sections)) {
|
|
@@ -17299,24 +17658,24 @@ ${body}${body ? "\n" : ""}`;
|
|
|
17299
17658
|
return { content, body };
|
|
17300
17659
|
}
|
|
17301
17660
|
function writeEntryFile(filePath, content) {
|
|
17302
|
-
const dir =
|
|
17303
|
-
if (!
|
|
17304
|
-
|
|
17661
|
+
const dir = dirname9(filePath);
|
|
17662
|
+
if (!existsSync17(dir)) mkdirSync10(dir, { recursive: true });
|
|
17663
|
+
writeFileSync10(filePath, content, "utf-8");
|
|
17305
17664
|
}
|
|
17306
17665
|
|
|
17307
17666
|
// ../../packages/core/dist/record.js
|
|
17308
|
-
import { statSync as
|
|
17309
|
-
import { join as
|
|
17667
|
+
import { statSync as statSync9 } from "node:fs";
|
|
17668
|
+
import { join as join15 } from "node:path";
|
|
17310
17669
|
var DEFAULT_CATEGORY = "misc";
|
|
17311
17670
|
function recordEntry(input, opts) {
|
|
17312
|
-
const
|
|
17671
|
+
const now2 = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
17313
17672
|
const source = opts.source ?? "own";
|
|
17314
|
-
const nowDate =
|
|
17673
|
+
const nowDate = now2();
|
|
17315
17674
|
const ymd = formatYmd(nowDate);
|
|
17316
|
-
const baseId = input.id ?? slugify(input.title,
|
|
17675
|
+
const baseId = input.id ?? slugify(input.title, now2);
|
|
17317
17676
|
const id = resolveCollision(baseId, (candidate) => entryExists(opts.db, source, candidate));
|
|
17318
17677
|
const mergedEnv = {
|
|
17319
|
-
...
|
|
17678
|
+
...fingerprint2(),
|
|
17320
17679
|
...input.environment ?? {}
|
|
17321
17680
|
};
|
|
17322
17681
|
const frontmatter = {
|
|
@@ -17328,7 +17687,7 @@ function recordEntry(input, opts) {
|
|
|
17328
17687
|
tags: input.tags ?? [],
|
|
17329
17688
|
environment: mergedEnv,
|
|
17330
17689
|
source_project: null,
|
|
17331
|
-
source_session: generateSourceSession(
|
|
17690
|
+
source_session: generateSourceSession(now2),
|
|
17332
17691
|
created_at: ymd,
|
|
17333
17692
|
updated_at: ymd,
|
|
17334
17693
|
last_verified: ymd
|
|
@@ -17342,9 +17701,9 @@ function recordEntry(input, opts) {
|
|
|
17342
17701
|
const built = buildEntry(frontmatter, sections);
|
|
17343
17702
|
const category = input.category ?? DEFAULT_CATEGORY;
|
|
17344
17703
|
const relPath = `${category}/${id}.md`;
|
|
17345
|
-
const filePath =
|
|
17704
|
+
const filePath = join15(opts.entriesRoot, relPath);
|
|
17346
17705
|
writeEntryFile(filePath, built.content);
|
|
17347
|
-
const stat =
|
|
17706
|
+
const stat = statSync9(filePath);
|
|
17348
17707
|
upsertEntry(opts.db, {
|
|
17349
17708
|
id,
|
|
17350
17709
|
source,
|
|
@@ -17372,8 +17731,8 @@ function formatYmd(d) {
|
|
|
17372
17731
|
}
|
|
17373
17732
|
|
|
17374
17733
|
// ../../packages/core/dist/update.js
|
|
17375
|
-
import { readFileSync as
|
|
17376
|
-
import { join as
|
|
17734
|
+
import { readFileSync as readFileSync14, statSync as statSync10, writeFileSync as writeFileSync11 } from "node:fs";
|
|
17735
|
+
import { join as join16 } from "node:path";
|
|
17377
17736
|
var IMMUTABLE_KEYS = /* @__PURE__ */ new Set([
|
|
17378
17737
|
"id",
|
|
17379
17738
|
"created_at",
|
|
@@ -17385,15 +17744,15 @@ function updateEntry(id, patch, opts) {
|
|
|
17385
17744
|
if (source !== "own") {
|
|
17386
17745
|
throw new Error("community \u30A8\u30F3\u30C8\u30EA\u306F\u8CFC\u8AAD\u7269\u3067\u3059; \u7DE8\u96C6\u306F\u4E0A\u6D41\u3067\u884C\u3063\u3066\u304F\u3060\u3055\u3044");
|
|
17387
17746
|
}
|
|
17388
|
-
const
|
|
17389
|
-
const nowDate =
|
|
17747
|
+
const now2 = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
17748
|
+
const nowDate = now2();
|
|
17390
17749
|
const row = opts.db.prepare("SELECT path FROM entries WHERE source = ? AND id = ?").get(source, id);
|
|
17391
17750
|
if (!row) {
|
|
17392
17751
|
throw new Error(`caveat not found: id=${id} source=${source}`);
|
|
17393
17752
|
}
|
|
17394
17753
|
const relPath = row.path;
|
|
17395
|
-
const filePath =
|
|
17396
|
-
const raw =
|
|
17754
|
+
const filePath = join16(opts.entriesRoot, relPath);
|
|
17755
|
+
const raw = readFileSync14(filePath, "utf-8");
|
|
17397
17756
|
const parsed = parseMarkdown(raw);
|
|
17398
17757
|
if (patch.frontmatter) {
|
|
17399
17758
|
for (const key of Object.keys(patch.frontmatter)) {
|
|
@@ -17434,8 +17793,8 @@ function updateEntry(id, patch, opts) {
|
|
|
17434
17793
|
}
|
|
17435
17794
|
}
|
|
17436
17795
|
const built = buildEntry(mergedFrontmatter, mergedSections);
|
|
17437
|
-
|
|
17438
|
-
const stat =
|
|
17796
|
+
writeFileSync11(filePath, built.content, "utf-8");
|
|
17797
|
+
const stat = statSync10(filePath);
|
|
17439
17798
|
upsertEntry(opts.db, {
|
|
17440
17799
|
id,
|
|
17441
17800
|
source,
|
|
@@ -17459,15 +17818,15 @@ function formatYmd2(d) {
|
|
|
17459
17818
|
}
|
|
17460
17819
|
|
|
17461
17820
|
// ../../packages/core/dist/proposalEval.js
|
|
17462
|
-
import { createHash as
|
|
17821
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
17463
17822
|
import { isAbsolute as isAbsolute2, relative as relative4, resolve as resolve4, sep } from "node:path";
|
|
17464
17823
|
|
|
17465
17824
|
// ../../packages/core/dist/proposalExecution.js
|
|
17466
|
-
import { createHash as
|
|
17825
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
17467
17826
|
import { basename as basename3, isAbsolute as isAbsolute3 } from "node:path";
|
|
17468
17827
|
|
|
17469
17828
|
// ../../packages/core/dist/proposalExecutionCompiler.js
|
|
17470
|
-
import { createHash as
|
|
17829
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
17471
17830
|
|
|
17472
17831
|
export {
|
|
17473
17832
|
__commonJS,
|
|
@@ -17498,9 +17857,11 @@ export {
|
|
|
17498
17857
|
KNOWLEDGE_GITIGNORE,
|
|
17499
17858
|
initOwnSync,
|
|
17500
17859
|
AUTO_SYNC_DEBOUNCE_MS,
|
|
17860
|
+
AUTO_SYNC_RECORD_DEBOUNCE_MS,
|
|
17501
17861
|
CAVEAT_AUTO_SYNC_ENV,
|
|
17502
17862
|
resetAutoSyncFailureState,
|
|
17503
17863
|
runAutoSync,
|
|
17864
|
+
triggerAutoSync,
|
|
17504
17865
|
search,
|
|
17505
17866
|
get,
|
|
17506
17867
|
listRecent,
|
|
@@ -17531,7 +17892,13 @@ export {
|
|
|
17531
17892
|
decideCodexSidecarExecution,
|
|
17532
17893
|
buildCodexSidecarDiagnosticsCommand,
|
|
17533
17894
|
buildCodexSidecarReadOnlySmokeCommand,
|
|
17534
|
-
buildCodexSidecarRunCommand
|
|
17895
|
+
buildCodexSidecarRunCommand,
|
|
17896
|
+
runtimeErrorsDiagnostics,
|
|
17897
|
+
observeRuntimeError,
|
|
17898
|
+
runtimeErrorsSnapshot,
|
|
17899
|
+
acknowledgeRuntimeErrors,
|
|
17900
|
+
setRuntimeErrorStatus,
|
|
17901
|
+
compactRuntimeErrors
|
|
17535
17902
|
};
|
|
17536
17903
|
/*! Bundled license information:
|
|
17537
17904
|
|
|
@@ -17554,4 +17921,4 @@ strip-bom-string/index.js:
|
|
|
17554
17921
|
js-yaml/dist/js-yaml.mjs:
|
|
17555
17922
|
(*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT *)
|
|
17556
17923
|
*/
|
|
17557
|
-
//# sourceMappingURL=chunk-
|
|
17924
|
+
//# sourceMappingURL=chunk-7FEOFAMA.js.map
|