@ouro.bot/cli 0.1.0-alpha.580 → 0.1.0-alpha.582
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/changelog.json +14 -0
- package/dist/heart/daemon/doctor.js +56 -9
- package/dist/senses/bluebubbles/index.js +68 -1
- package/dist/trips/store.js +119 -0
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.582",
|
|
6
|
+
"changes": [
|
|
7
|
+
"BlueBubbles now suppresses same-turn near-duplicate outward sends using token/Jaccard similarity, covering rewritten retry answers, repeated status messages, and retry-loop variants without blocking short distinct replies.",
|
|
8
|
+
"BlueBubbles status sends now pass through the same duplicate guard as normal outward text, preserving inner/meta leak protections while reducing repeated iMessage status loops."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"version": "0.1.0-alpha.581",
|
|
13
|
+
"changes": [
|
|
14
|
+
"Trip ledger storage now uses git-controlled bundle-root `trips/` as canonical local storage, with copy-only import from legacy ignored `state/trips/` and divergence warnings instead of silent merges.",
|
|
15
|
+
"`ouro doctor` now checks durable trip ledgers and reports legacy-only or divergent `state/trips/` data clearly so bundle sync and backup gaps surface before travel facts are lost."
|
|
16
|
+
]
|
|
17
|
+
},
|
|
4
18
|
{
|
|
5
19
|
"version": "0.1.0-alpha.580",
|
|
6
20
|
"changes": [
|
|
@@ -373,15 +373,27 @@ function checkTrips(deps) {
|
|
|
373
373
|
return { name: "Trips", checks };
|
|
374
374
|
}
|
|
375
375
|
for (const agentDir of agents) {
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
376
|
+
const durableTripsRoot = `${deps.bundlesRoot}/${agentDir}/trips`;
|
|
377
|
+
const legacyTripsRoot = `${deps.bundlesRoot}/${agentDir}/state/trips`;
|
|
378
|
+
const hasDurableTrips = deps.existsSync(durableTripsRoot);
|
|
379
|
+
const hasLegacyTrips = deps.existsSync(legacyTripsRoot);
|
|
380
|
+
if (!hasDurableTrips) {
|
|
381
|
+
if (hasLegacyTrips) {
|
|
382
|
+
checks.push({
|
|
383
|
+
label: `${agentDir} trip ledger`,
|
|
384
|
+
status: "warn",
|
|
385
|
+
detail: "legacy state/trips exists but durable trips/ missing — run any trip tool to copy legacy storage into trips/",
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// Trip ledger is optional; absence is fine. Pass with a hint.
|
|
390
|
+
checks.push({ label: `${agentDir} trip ledger`, status: "pass", detail: "no ledger directory (no trips ensured yet)" });
|
|
391
|
+
}
|
|
380
392
|
continue;
|
|
381
393
|
}
|
|
382
|
-
const ledgerPath = `${
|
|
394
|
+
const ledgerPath = `${durableTripsRoot}/ledger.json`;
|
|
383
395
|
if (!deps.existsSync(ledgerPath)) {
|
|
384
|
-
checks.push({ label: `${agentDir} trip ledger`, status: "warn", detail: "
|
|
396
|
+
checks.push({ label: `${agentDir} trip ledger`, status: "warn", detail: "trips/ exists but ledger.json missing — run trip_ensure_ledger" });
|
|
385
397
|
continue;
|
|
386
398
|
}
|
|
387
399
|
let raw;
|
|
@@ -420,7 +432,7 @@ function checkTrips(deps) {
|
|
|
420
432
|
continue;
|
|
421
433
|
}
|
|
422
434
|
let recordCount = 0;
|
|
423
|
-
const recordsDir = `${
|
|
435
|
+
const recordsDir = `${durableTripsRoot}/records`;
|
|
424
436
|
/* v8 ignore start -- defensive: records dir presence and readdir error are filesystem-state branches not all exercised by tests; pluralization branch likewise depends on record count fixtures @preserve */
|
|
425
437
|
if (deps.existsSync(recordsDir)) {
|
|
426
438
|
try {
|
|
@@ -430,15 +442,50 @@ function checkTrips(deps) {
|
|
|
430
442
|
// ignore — the warn detail will still report 0 records
|
|
431
443
|
}
|
|
432
444
|
}
|
|
445
|
+
const legacyDiverges = hasLegacyTrips && tripStoresDiffer(deps, durableTripsRoot, legacyTripsRoot);
|
|
433
446
|
checks.push({
|
|
434
447
|
label: `${agentDir} trip ledger`,
|
|
435
|
-
status: "pass",
|
|
436
|
-
detail: `${ledgerId} (${recordCount} record${recordCount === 1 ? "" : "s"})`,
|
|
448
|
+
status: legacyDiverges ? "warn" : "pass",
|
|
449
|
+
detail: `${ledgerId} (${recordCount} record${recordCount === 1 ? "" : "s"})${legacyDiverges ? "; legacy state/trips differs from durable trips/ — durable trips/ is authoritative" : ""}`,
|
|
437
450
|
});
|
|
438
451
|
/* v8 ignore stop */
|
|
439
452
|
}
|
|
440
453
|
return { name: "Trips", checks };
|
|
441
454
|
}
|
|
455
|
+
function listTripStoreFiles(deps, root) {
|
|
456
|
+
const files = [];
|
|
457
|
+
if (deps.existsSync(`${root}/ledger.json`)) {
|
|
458
|
+
files.push("ledger.json");
|
|
459
|
+
}
|
|
460
|
+
const recordsDir = `${root}/records`;
|
|
461
|
+
if (deps.existsSync(recordsDir)) {
|
|
462
|
+
for (const name of deps.readdirSync(recordsDir)) {
|
|
463
|
+
if (name.endsWith(".json")) {
|
|
464
|
+
files.push(`records/${name}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return files.sort();
|
|
469
|
+
}
|
|
470
|
+
function tripStoresDiffer(deps, durableRoot, legacyRoot) {
|
|
471
|
+
const relativePaths = new Set([
|
|
472
|
+
...listTripStoreFiles(deps, durableRoot),
|
|
473
|
+
...listTripStoreFiles(deps, legacyRoot),
|
|
474
|
+
]);
|
|
475
|
+
for (const relativePath of relativePaths) {
|
|
476
|
+
const durablePath = `${durableRoot}/${relativePath}`;
|
|
477
|
+
const legacyPath = `${legacyRoot}/${relativePath}`;
|
|
478
|
+
const durableExists = deps.existsSync(durablePath);
|
|
479
|
+
const legacyExists = deps.existsSync(legacyPath);
|
|
480
|
+
if (durableExists !== legacyExists) {
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
if (durableExists && deps.readFileSync(durablePath) !== deps.readFileSync(legacyPath)) {
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
442
489
|
function checkMailroom(deps) {
|
|
443
490
|
const checks = [];
|
|
444
491
|
const agents = discoverAgents(deps);
|
|
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.enrichReactionText = enrichReactionText;
|
|
37
|
+
exports.tokenizeForDedupe = tokenizeForDedupe;
|
|
38
|
+
exports.jaccardSimilarity = jaccardSimilarity;
|
|
37
39
|
exports.createStatusBatcher = createStatusBatcher;
|
|
38
40
|
exports.createBlueBubblesCallbacks = createBlueBubblesCallbacks;
|
|
39
41
|
exports.isAgentSelfHandle = isAgentSelfHandle;
|
|
@@ -95,6 +97,29 @@ function enrichReactionText(baseText, originalText, maxLen) {
|
|
|
95
97
|
: originalText;
|
|
96
98
|
return `${baseText} to: "${truncated}"`;
|
|
97
99
|
}
|
|
100
|
+
// ── Near-duplicate outward-text detection ────────────────────────
|
|
101
|
+
// Used by createBlueBubblesCallbacks to collapse mid-turn rephrasings of the
|
|
102
|
+
// same answer/status into a single delivery. Exposed for direct unit testing
|
|
103
|
+
// of the similarity behavior without spinning up the full callbacks closure.
|
|
104
|
+
const NEAR_DUPLICATE_JACCARD_THRESHOLD = 0.7;
|
|
105
|
+
const NEAR_DUPLICATE_MIN_TOKENS = 5;
|
|
106
|
+
function tokenizeForDedupe(text) {
|
|
107
|
+
const matches = text.toLowerCase().match(/[a-z0-9']+/g);
|
|
108
|
+
if (!matches)
|
|
109
|
+
return new Set();
|
|
110
|
+
return new Set(matches);
|
|
111
|
+
}
|
|
112
|
+
function jaccardSimilarity(a, b) {
|
|
113
|
+
if (a.size === 0 || b.size === 0)
|
|
114
|
+
return 0;
|
|
115
|
+
let intersection = 0;
|
|
116
|
+
for (const token of a) {
|
|
117
|
+
if (b.has(token))
|
|
118
|
+
intersection += 1;
|
|
119
|
+
}
|
|
120
|
+
const union = a.size + b.size - intersection;
|
|
121
|
+
return intersection / union;
|
|
122
|
+
}
|
|
98
123
|
/**
|
|
99
124
|
* Accumulates status descriptions and debounces them.
|
|
100
125
|
* If multiple descriptions arrive within `delayMs`, they are joined with ` · `
|
|
@@ -466,7 +491,16 @@ function createBlueBubblesCallbacks(client, chat, replyTarget, isGroupChat, onVi
|
|
|
466
491
|
// final flush, surfacing as 4 near-identical iMessages from one ask
|
|
467
492
|
// (2026-05-08 06:18 incident). The guard lets the engine retry harmlessly
|
|
468
493
|
// without duplicating outward delivery to the friend.
|
|
494
|
+
//
|
|
495
|
+
// PR #699 used exact whitespace+case-normalized match. Post-#699 evidence
|
|
496
|
+
// (2026-05-09 05:25 UTC, evt-001814 + evt-001818) showed two answers that
|
|
497
|
+
// start "yep — I looked it up… Assuming you mean AMC's The Audacity…" with
|
|
498
|
+
// substantially the same content but slight rephrasing — the LLM rewrites
|
|
499
|
+
// the same answer on a retry/recovery loop and bypasses an exact-match
|
|
500
|
+
// guard. We now also keep the original token sets so a fuzzy (Jaccard)
|
|
501
|
+
// check catches near-duplicates from the same turn.
|
|
469
502
|
const sentOutwardTextNorms = new Set();
|
|
503
|
+
const sentOutwardTokenSets = [];
|
|
470
504
|
function enqueue(operation, task) {
|
|
471
505
|
queue = queue.then(task).catch((error) => {
|
|
472
506
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -504,7 +538,25 @@ function createBlueBubblesCallbacks(client, chat, replyTarget, isGroupChat, onVi
|
|
|
504
538
|
const norm = trimmed.replace(/\s+/g, " ").trim().toLowerCase();
|
|
505
539
|
if (sentOutwardTextNorms.has(norm))
|
|
506
540
|
return true;
|
|
541
|
+
// Fuzzy near-duplicate: when the same answer is rephrased between speak
|
|
542
|
+
// and settle (or across two speak calls in a recovery loop), the exact
|
|
543
|
+
// norm differs but token overlap is very high. We compare against every
|
|
544
|
+
// already-sent body's token set; if any has Jaccard overlap >= the
|
|
545
|
+
// threshold, treat as a duplicate. We require a minimum token count on
|
|
546
|
+
// the new body so single-word replies ("yes", "ok") don't get suppressed
|
|
547
|
+
// against any previous short one with shared tokens.
|
|
548
|
+
const newTokens = tokenizeForDedupe(trimmed);
|
|
549
|
+
if (newTokens.size >= NEAR_DUPLICATE_MIN_TOKENS) {
|
|
550
|
+
for (const prevTokens of sentOutwardTokenSets) {
|
|
551
|
+
if (prevTokens.size < NEAR_DUPLICATE_MIN_TOKENS)
|
|
552
|
+
continue;
|
|
553
|
+
if (jaccardSimilarity(newTokens, prevTokens) >= NEAR_DUPLICATE_JACCARD_THRESHOLD) {
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
507
558
|
sentOutwardTextNorms.add(norm);
|
|
559
|
+
sentOutwardTokenSets.push(newTokens);
|
|
508
560
|
return false;
|
|
509
561
|
}
|
|
510
562
|
function emitDuplicateOutwardSuppressed(site, messageLength) {
|
|
@@ -540,10 +592,25 @@ function createBlueBubblesCallbacks(client, chat, replyTarget, isGroupChat, onVi
|
|
|
540
592
|
}
|
|
541
593
|
}
|
|
542
594
|
function sendStatus(text) {
|
|
595
|
+
const trimmed = text.trim();
|
|
596
|
+
/* v8 ignore next -- defensive guard; current status callers always provide non-empty text @preserve */
|
|
597
|
+
if (!trimmed)
|
|
598
|
+
return;
|
|
599
|
+
// Status surfaces share the per-turn dedupe set so a status-style
|
|
600
|
+
// outward message (tool description, error notice, watchdog ping)
|
|
601
|
+
// can't deliver a near-duplicate of an already-sent answer or status
|
|
602
|
+
// (post-#699 evidence: evt-001820 + evt-001821 + evt-001823 on
|
|
603
|
+
// 2026-05-09 — overlapping status surface updates about the same
|
|
604
|
+
// duplicate issue, which the flushNow/flush-only guard could not catch
|
|
605
|
+
// because sendStatus writes directly via client.sendText).
|
|
606
|
+
if (isDuplicateOutwardText(trimmed)) {
|
|
607
|
+
emitDuplicateOutwardSuppressed("status", trimmed.length);
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
543
610
|
enqueue("send_status", async () => {
|
|
544
611
|
await client.sendText({
|
|
545
612
|
chat,
|
|
546
|
-
text,
|
|
613
|
+
text: trimmed,
|
|
547
614
|
replyToMessageGuid: replyTarget.getReplyToMessageGuid(),
|
|
548
615
|
});
|
|
549
616
|
recordVisibleActivity();
|
package/dist/trips/store.js
CHANGED
|
@@ -45,6 +45,9 @@ const identity_1 = require("../heart/identity");
|
|
|
45
45
|
const runtime_1 = require("../nerves/runtime");
|
|
46
46
|
const core_1 = require("./core");
|
|
47
47
|
function tripsRoot(agentName) {
|
|
48
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "trips");
|
|
49
|
+
}
|
|
50
|
+
function legacyTripsRoot(agentName) {
|
|
48
51
|
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "trips");
|
|
49
52
|
}
|
|
50
53
|
function ledgerPath(agentName) {
|
|
@@ -56,6 +59,118 @@ function recordsDir(agentName) {
|
|
|
56
59
|
function recordPath(agentName, tripId) {
|
|
57
60
|
return path.join(recordsDir(agentName), `${tripId}.json`);
|
|
58
61
|
}
|
|
62
|
+
function ledgerPathFor(root) {
|
|
63
|
+
return path.join(root, "ledger.json");
|
|
64
|
+
}
|
|
65
|
+
function recordsDirFor(root) {
|
|
66
|
+
return path.join(root, "records");
|
|
67
|
+
}
|
|
68
|
+
function removeMigrationTempRoot(tmpRoot) {
|
|
69
|
+
const records = recordsDirFor(tmpRoot);
|
|
70
|
+
if (fs.existsSync(records)) {
|
|
71
|
+
for (const entry of fs.readdirSync(records)) {
|
|
72
|
+
fs.unlinkSync(path.join(records, entry));
|
|
73
|
+
}
|
|
74
|
+
fs.rmdirSync(records);
|
|
75
|
+
}
|
|
76
|
+
const ledger = ledgerPathFor(tmpRoot);
|
|
77
|
+
if (fs.existsSync(ledger)) {
|
|
78
|
+
fs.unlinkSync(ledger);
|
|
79
|
+
}
|
|
80
|
+
if (fs.existsSync(tmpRoot)) {
|
|
81
|
+
fs.rmdirSync(tmpRoot);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function copyLegacyTripsIfNeeded(agentName) {
|
|
85
|
+
const durableRoot = tripsRoot(agentName);
|
|
86
|
+
const legacyRoot = legacyTripsRoot(agentName);
|
|
87
|
+
if (fs.existsSync(durableRoot) || !fs.existsSync(ledgerPathFor(legacyRoot))) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const tmpRoot = `${durableRoot}.tmp-${process.pid}-${Date.now()}`;
|
|
91
|
+
removeMigrationTempRoot(tmpRoot);
|
|
92
|
+
try {
|
|
93
|
+
fs.mkdirSync(recordsDirFor(tmpRoot), { recursive: true });
|
|
94
|
+
fs.copyFileSync(ledgerPathFor(legacyRoot), ledgerPathFor(tmpRoot));
|
|
95
|
+
const legacyRecordsDir = recordsDirFor(legacyRoot);
|
|
96
|
+
if (fs.existsSync(legacyRecordsDir)) {
|
|
97
|
+
for (const entry of fs.readdirSync(legacyRecordsDir)) {
|
|
98
|
+
if (entry.endsWith(".json")) {
|
|
99
|
+
fs.copyFileSync(path.join(legacyRecordsDir, entry), path.join(recordsDirFor(tmpRoot), entry));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
fs.renameSync(tmpRoot, durableRoot);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
removeMigrationTempRoot(tmpRoot);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function collectStoreFiles(root) {
|
|
111
|
+
const files = [];
|
|
112
|
+
if (fs.existsSync(ledgerPathFor(root))) {
|
|
113
|
+
files.push("ledger.json");
|
|
114
|
+
}
|
|
115
|
+
const records = recordsDirFor(root);
|
|
116
|
+
if (fs.existsSync(records)) {
|
|
117
|
+
for (const entry of fs.readdirSync(records)) {
|
|
118
|
+
if (entry.endsWith(".json")) {
|
|
119
|
+
files.push(`records/${entry}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return files.sort();
|
|
124
|
+
}
|
|
125
|
+
function fileAt(root, relativePath) {
|
|
126
|
+
return path.join(root, ...relativePath.split("/"));
|
|
127
|
+
}
|
|
128
|
+
function findLegacyDifferences(durableRoot, legacyRoot) {
|
|
129
|
+
const paths = new Set([...collectStoreFiles(durableRoot), ...collectStoreFiles(legacyRoot)]);
|
|
130
|
+
const differences = [];
|
|
131
|
+
for (const relativePath of [...paths].sort()) {
|
|
132
|
+
const durablePath = fileAt(durableRoot, relativePath);
|
|
133
|
+
const legacyPath = fileAt(legacyRoot, relativePath);
|
|
134
|
+
const durableExists = fs.existsSync(durablePath);
|
|
135
|
+
const legacyExists = fs.existsSync(legacyPath);
|
|
136
|
+
if (durableExists !== legacyExists) {
|
|
137
|
+
differences.push(relativePath);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (durableExists && !fs.readFileSync(durablePath).equals(fs.readFileSync(legacyPath))) {
|
|
141
|
+
differences.push(relativePath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return differences;
|
|
145
|
+
}
|
|
146
|
+
function reportLegacyDivergence(agentName) {
|
|
147
|
+
const durableRoot = tripsRoot(agentName);
|
|
148
|
+
const legacyRoot = legacyTripsRoot(agentName);
|
|
149
|
+
if (!fs.existsSync(durableRoot) || !fs.existsSync(legacyRoot)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const differences = findLegacyDifferences(durableRoot, legacyRoot);
|
|
153
|
+
if (differences.length === 0) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
(0, runtime_1.emitNervesEvent)({
|
|
157
|
+
level: "warn",
|
|
158
|
+
component: "trips",
|
|
159
|
+
event: "trips.legacy_diverged",
|
|
160
|
+
message: "legacy trip store differs from durable trip store",
|
|
161
|
+
meta: {
|
|
162
|
+
agentId: agentName,
|
|
163
|
+
durablePath: "trips",
|
|
164
|
+
legacyPath: "state/trips",
|
|
165
|
+
differenceCount: differences.length,
|
|
166
|
+
differences: differences.slice(0, 10),
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function prepareTripStorage(agentName) {
|
|
171
|
+
copyLegacyTripsIfNeeded(agentName);
|
|
172
|
+
reportLegacyDivergence(agentName);
|
|
173
|
+
}
|
|
59
174
|
function readJsonFile(filePath) {
|
|
60
175
|
if (!fs.existsSync(filePath))
|
|
61
176
|
return null;
|
|
@@ -79,6 +194,7 @@ exports.TripNotFoundError = TripNotFoundError;
|
|
|
79
194
|
* generate a fresh keypair and persist both halves.
|
|
80
195
|
*/
|
|
81
196
|
function ensureAgentTripLedger(input) {
|
|
197
|
+
prepareTripStorage(input.agentName);
|
|
82
198
|
const existing = readJsonFile(ledgerPath(input.agentName));
|
|
83
199
|
if (existing) {
|
|
84
200
|
return { ledger: existing.ledger, added: false };
|
|
@@ -103,6 +219,7 @@ function ensureAgentTripLedger(input) {
|
|
|
103
219
|
return { ledger: created.ledger, added: true };
|
|
104
220
|
}
|
|
105
221
|
function readLedgerOrThrow(agentName) {
|
|
222
|
+
prepareTripStorage(agentName);
|
|
106
223
|
const stored = readJsonFile(ledgerPath(agentName));
|
|
107
224
|
if (!stored) {
|
|
108
225
|
throw new Error(`no trip ledger for agent ${agentName} — call ensureAgentTripLedger first`);
|
|
@@ -129,6 +246,7 @@ function upsertTripRecord(agentName, trip) {
|
|
|
129
246
|
});
|
|
130
247
|
}
|
|
131
248
|
function readTripRecord(agentName, tripId) {
|
|
249
|
+
prepareTripStorage(agentName);
|
|
132
250
|
const payload = readJsonFile(recordPath(agentName, tripId));
|
|
133
251
|
if (!payload)
|
|
134
252
|
throw new TripNotFoundError({ agentName, tripId });
|
|
@@ -136,6 +254,7 @@ function readTripRecord(agentName, tripId) {
|
|
|
136
254
|
return (0, core_1.decryptTripRecord)(payload, stored.privateKeyPem);
|
|
137
255
|
}
|
|
138
256
|
function listTripIds(agentName) {
|
|
257
|
+
prepareTripStorage(agentName);
|
|
139
258
|
const dir = recordsDir(agentName);
|
|
140
259
|
if (!fs.existsSync(dir))
|
|
141
260
|
return [];
|