@evoclock/pi-agentic-driver 1.1.2 → 2.0.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/.agentic-driver/loop-until-done.defaults.json +5 -0
- package/README.md +302 -41
- package/config/merge-policy.v1.example.json +4 -0
- package/config/relay-authority.v1.example.json +7 -0
- package/config/treehouse.v1.json +4 -0
- package/docs/durable-driver-api.md +23 -0
- package/docs/durable-persistence.md +32 -0
- package/docs/merge-policy.md +45 -0
- package/docs/relay-authority.md +9 -0
- package/extensions/aidr.ts +3 -0
- package/extensions/harvest-lessons.ts +8 -0
- package/extensions/herdr-dispatch.ts +32 -3
- package/extensions/loop-until-done.ts +7 -0
- package/extensions/recovery-evidence.ts +3 -3
- package/extensions/treehouse-recycle.ts +47 -0
- package/janus/README.md +2 -4
- package/janus/janus/config.ts +2 -2
- package/janus/janus/providers.ts +2 -4
- package/janus/tests/providers.test.ts +2 -2
- package/{extensions → lib}/task-store-adapter.ts +1 -5
- package/package.json +158 -4
- package/scripts/enforcement/approval_ledger_pi.js +135 -0
- package/scripts/enforcement/attended_authority_guard.js +113 -0
- package/scripts/enforcement/board_claim_bridge_pi.js +10 -10
- package/scripts/enforcement/durable_assignment_pi.js +488 -0
- package/scripts/enforcement/durable_driver_pi.d.ts +51 -0
- package/scripts/enforcement/durable_driver_pi.js +254 -0
- package/scripts/enforcement/herdr_async_dispatch_pi.js +86 -20
- package/scripts/enforcement/herdr_async_seam_pi.js +90 -3
- package/scripts/enforcement/herdr_communication_pi.js +126 -12
- package/scripts/enforcement/herdr_lifecycle_pi.js +730 -81
- package/scripts/enforcement/linux_microvm_cutover_pi.js +3 -3
- package/scripts/enforcement/linux_microvm_remote_fixture.sh +0 -6
- package/scripts/enforcement/loop_until_done_guide.md +13 -0
- package/scripts/enforcement/loop_until_done_pi.js +214 -0
- package/scripts/enforcement/merge_policy.js +181 -0
- package/scripts/enforcement/outward_effect_pi.js +156 -0
- package/scripts/enforcement/recovery_evidence_review_pi.js +31 -3
- package/scripts/enforcement/storage_owner_lock_pi.js +66 -0
- package/scripts/enforcement/task_board_core_pi.js +13 -100
- package/scripts/enforcement/task_board_hash_pi.js +86 -0
- package/scripts/enforcement/treehouse_recycle_pi.js +145 -0
- package/scripts/harvest_lessons.js +219 -0
- package/scripts/relay/record_approval.mjs +10 -0
- package/scripts/relay/send_request.mjs +26 -0
- package/skills/architect-pi/SKILL.md +44 -0
- package/skills/arena-pi/SKILL.md +46 -0
- package/skills/automate-me-pi/SKILL.md +37 -0
- package/skills/benchmark-checklist-pi/SKILL.md +35 -0
- package/skills/blast-radius-pi/SKILL.md +24 -0
- package/skills/bro-pi/SKILL.md +17 -0
- package/skills/correct-pi/SKILL.md +36 -0
- package/skills/create-verification-skill-pi/LICENSE +21 -0
- package/skills/create-verification-skill-pi/SKILL.md +24 -0
- package/skills/decision-to-spec/SKILL.md +5 -5
- package/skills/figure-it-out-pi/SKILL.md +37 -0
- package/skills/harvest-lessons/SKILL.md +56 -0
- package/skills/harvest-lessons/harvest.example.json +8 -0
- package/skills/how/LICENSE +24 -0
- package/skills/how/WORKFLOW_BOUNDARIES.md +19 -0
- package/skills/how-pi/SKILL.md +33 -0
- package/skills/in-your-own-words-pi/SKILL.md +15 -0
- package/skills/interrogate-pi/SKILL.md +35 -0
- package/skills/ketchup-pi/SKILL.md +21 -0
- package/skills/maintain-verification-skill-pi/SKILL.md +37 -0
- package/skills/make-bot-ui-pi/SKILL.md +33 -0
- package/skills/no-comments-pi/SKILL.md +33 -0
- package/skills/poteto-help-pi/SKILL.md +50 -0
- package/skills/poteto-mode-pi/LICENSE +21 -0
- package/skills/poteto-mode-pi/SKILL.md +41 -0
- package/skills/poteto-mode-pi/playbooks.md +95 -0
- package/skills/principle-attack-the-premise-pi/SKILL.md +17 -0
- package/skills/principle-boundary-discipline-pi/SKILL.md +19 -0
- package/skills/principle-build-the-lever-pi/SKILL.md +19 -0
- package/skills/principle-encode-lessons-in-structure-pi/SKILL.md +17 -0
- package/skills/principle-exhaust-the-design-space-pi/SKILL.md +17 -0
- package/skills/principle-experience-first-pi/SKILL.md +17 -0
- package/skills/principle-explain-the-number-pi/SKILL.md +21 -0
- package/skills/principle-fix-root-causes-pi/SKILL.md +21 -0
- package/skills/principle-foundational-thinking-pi/SKILL.md +21 -0
- package/skills/principle-guard-the-context-window-pi/SKILL.md +19 -0
- package/skills/principle-laziness-protocol-pi/SKILL.md +19 -0
- package/skills/principle-make-operations-idempotent-pi/SKILL.md +21 -0
- package/skills/principle-migrate-callers-then-delete-legacy-apis-pi/SKILL.md +19 -0
- package/skills/principle-minimize-reader-load-pi/SKILL.md +19 -0
- package/skills/principle-model-the-domain-pi/SKILL.md +19 -0
- package/skills/principle-never-block-on-the-human-pi/SKILL.md +19 -0
- package/skills/principle-outcome-oriented-execution-pi/SKILL.md +19 -0
- package/skills/principle-prove-it-works-pi/SKILL.md +19 -0
- package/skills/principle-redesign-from-first-principles-pi/SKILL.md +19 -0
- package/skills/principle-separate-before-serializing-shared-state-pi/SKILL.md +19 -0
- package/skills/principle-sequence-verifiable-units-pi/SKILL.md +19 -0
- package/skills/principle-subtract-before-you-add-pi/SKILL.md +19 -0
- package/skills/principle-test-behavior-not-implementation-pi/SKILL.md +21 -0
- package/skills/principle-type-system-discipline-pi/SKILL.md +19 -0
- package/skills/public-pr-wording/SKILL.md +69 -0
- package/skills/public-pr-wording/pr_wording_config.example.json +22 -0
- package/skills/public-pr-wording/pr_wording_lint.py +249 -0
- package/skills/public-pr-wording/pr_wording_rules.json +60 -0
- package/skills/pulse/SKILL.md +6 -0
- package/skills/recall-pi/SKILL.md +29 -0
- package/skills/reflect-pi/SKILL.md +27 -0
- package/skills/setup-pstack-pi/SKILL.md +23 -0
- package/skills/setup-pstack-pi/assets/pstack-model-roles.v1.example.json +7 -0
- package/skills/sharpen-pi/SKILL.md +19 -0
- package/skills/show-me-your-work-pi/SKILL.md +27 -0
- package/skills/swarm-pi/SKILL.md +27 -0
- package/skills/tasks/SKILL.md +8 -2
- package/skills/tdd-pi/SKILL.md +21 -0
- package/skills/teach-pi/SKILL.md +21 -0
- package/skills/technical-writing-pi/SKILL.md +27 -0
- package/skills/typescript-best-practices-pi/SKILL.md +21 -0
- package/skills/unslop-pi/SKILL.md +27 -0
- package/skills/why-pi/SKILL.md +37 -0
|
@@ -219,7 +219,7 @@ function boundedString(value, field, maxBytes = MAX_PROCESS_OUTPUT_BYTES) {
|
|
|
219
219
|
return value;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
function expectedRepository(context) {
|
|
222
|
+
export function expectedRepository(context) {
|
|
223
223
|
const value = context?.repository ?? context?.cwd;
|
|
224
224
|
if (typeof value !== "string" || !value.trim()) {
|
|
225
225
|
throw communicationError("repository_unavailable", "the current repository is unavailable");
|
|
@@ -303,7 +303,7 @@ function checkedRegistryPath(primary) {
|
|
|
303
303
|
// Registry lookup order (coordinator decision): the session repository's
|
|
304
304
|
// own config first; when missing (ENOENT only) the active Pi profile's
|
|
305
305
|
// shared config under {PI_CODING_AGENT_DIR}/config/ (fallback
|
|
306
|
-
//
|
|
306
|
+
// the installed agent config directory). When neither exists, return the repo-local path so
|
|
307
307
|
// the caller's primary-only fallback applies exactly as before.
|
|
308
308
|
const profileDir = process.env.PI_CODING_AGENT_DIR;
|
|
309
309
|
const base = typeof profileDir === "string" && profileDir.trim()
|
|
@@ -1257,10 +1257,81 @@ export function extractLatestHerdrReport(text, role) {
|
|
|
1257
1257
|
// ---------------------------------------------------------------------------
|
|
1258
1258
|
|
|
1259
1259
|
const deliveries = new Map();
|
|
1260
|
+
let offlineDeliveries = new WeakMap();
|
|
1260
1261
|
let deliverySeq = 0;
|
|
1261
1262
|
|
|
1263
|
+
function deliveryRecords(options) {
|
|
1264
|
+
if (!options.offlinePersistence) return deliveries;
|
|
1265
|
+
if (!offlineDeliveries.has(options.offlinePersistence)) offlineDeliveries.set(options.offlinePersistence, new Map());
|
|
1266
|
+
return offlineDeliveries.get(options.offlinePersistence);
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
function requireOfflinePersistence(options) {
|
|
1270
|
+
const store = options.offlinePersistence;
|
|
1271
|
+
if (!store) return;
|
|
1272
|
+
if (store.schema !== "agentic-driver.offline-seam-store.v1" || typeof options.runProcess !== "function" ||
|
|
1273
|
+
["get", "reserve", "update"].some((name) => typeof store[name] !== "function")) {
|
|
1274
|
+
throw communicationError("offline_persistence_required", "persistence requires the offline store and injected process adapter", "denied");
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
async function deliverPersistedPrompt(operation, request, context, options, signal, repositories) {
|
|
1279
|
+
const repository = expectedRepository(context);
|
|
1280
|
+
const digest = createHash("sha256").update(JSON.stringify({ repository, role: request.role, prompt: request.prompt })).digest("hex");
|
|
1281
|
+
const requestId = options.offlineRequestId ?? digest;
|
|
1282
|
+
if (typeof requestId !== "string" || !/^[a-z0-9-]{1,128}$/.test(requestId)) throw communicationError("offline_request_invalid", "bounded offline request identity required", "denied");
|
|
1283
|
+
const identity = createHash("sha256").update(`${repository}\u0000${requestId}`).digest("hex");
|
|
1284
|
+
// Retain the existing correlation grammar; the suffix is opaque, not a clock.
|
|
1285
|
+
const id = `dlv-${identity.slice(0, 16)}-${identity.slice(16, 32)}`;
|
|
1286
|
+
// Validate the complete framed brief before leaving a persistent tombstone.
|
|
1287
|
+
promptWithReportRequirement(request.role, request.prompt, id);
|
|
1288
|
+
const store = options.offlinePersistence;
|
|
1289
|
+
const reserved = await store.reserve("delivery", { id, digest, repository, role: request.role, createdAt: Date.now(), state: "queued" });
|
|
1290
|
+
if (!reserved.created) {
|
|
1291
|
+
const accepted = ["delivered", "answered"].includes(reserved.record.state);
|
|
1292
|
+
return { schema: HERDR_COMMUNICATION_SCHEMA, ok: accepted, status: accepted ? "accepted" : "refused", operation,
|
|
1293
|
+
deliveryId: id, role: request.role, deliveryState: reserved.record.state, acceptedAt: reserved.record.acceptedAt,
|
|
1294
|
+
duplicate: true, promptSent: false, held: !accepted, persisted: true, nonAuthorizing: true, authorityCreated: false };
|
|
1295
|
+
}
|
|
1296
|
+
await options.offlineBoundary?.("after-delivery-intent", { deliveryId: id });
|
|
1297
|
+
const sent = await deliverPrompt(operation, request, context, { ...options, offlineDeliveryId: id }, signal, repositories);
|
|
1298
|
+
await options.offlineBoundary?.("after-delivery-send", { deliveryId: id });
|
|
1299
|
+
const latest = await store.get("delivery", id);
|
|
1300
|
+
const patch = { state: latest.state === "held" ? "held" : sent.deliveryState ?? "failed" };
|
|
1301
|
+
if (sent.acceptedAt) patch.acceptedAt = sent.acceptedAt;
|
|
1302
|
+
if (sent.code) patch.code = sent.code;
|
|
1303
|
+
const committed = await store.update("delivery", id, digest, patch);
|
|
1304
|
+
await options.offlineBoundary?.("after-delivery-ack", { deliveryId: id });
|
|
1305
|
+
return { ...sent, ...(committed.state === "held" ? { ok: false, status: "refused", held: true, deliveryState: "unknown" } : {}), deliveryId: id, persisted: true };
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
async function queryPersistedDelivery(request, context, options, signal, repositories) {
|
|
1309
|
+
const store = options.offlinePersistence;
|
|
1310
|
+
const saved = await store.get("delivery", request.deliveryId);
|
|
1311
|
+
if (!saved) return deliveryRefusal("delivery", communicationError("delivery_unknown", "no persisted delivery is known"));
|
|
1312
|
+
if (saved.repository !== expectedRepository(context)) throw communicationError("repository_mismatch", "delivery belongs to another repository", "denied");
|
|
1313
|
+
requireRole(saved.role);
|
|
1314
|
+
if (saved.state === "held") return deliverySnapshot({ ...saved, deliveryId: saved.id, state: "unknown" }, { held: true, code: saved.code ?? "delivery-held", persisted: true });
|
|
1315
|
+
if (saved.state === "answered" && saved.proof === "snapshot-backed-v1") {
|
|
1316
|
+
return deliverySnapshot({ ...saved, deliveryId: saved.id }, { report: saved.report, reportMarkers: reportMarkersForRole(saved.role), answeredAt: saved.answeredAt, persisted: true });
|
|
1317
|
+
}
|
|
1318
|
+
if (!deliveryRecords(options).has(saved.id)) {
|
|
1319
|
+
// Neither terminal snapshots nor framed echoes are restored from disk.
|
|
1320
|
+
// Original proof lost means hold, even if the role is now idle/done.
|
|
1321
|
+
if (saved.state !== "failed" && saved.state !== "held") await store.update("delivery", saved.id, saved.digest, { state: "held", code: "attribution-lost" });
|
|
1322
|
+
return deliverySnapshot({ ...saved, deliveryId: saved.id, state: saved.state === "failed" ? "failed" : "unknown" },
|
|
1323
|
+
{ held: saved.state !== "failed", code: saved.state === "failed" ? saved.code : "attribution-lost", persisted: true });
|
|
1324
|
+
}
|
|
1325
|
+
const observed = await queryDelivery(request, context, options, signal, repositories);
|
|
1326
|
+
if (observed.deliveryState === "answered") {
|
|
1327
|
+
await store.update("delivery", saved.id, saved.digest, { state: "answered", report: observed.report, answeredAt: observed.answeredAt, proof: "snapshot-backed-v1" });
|
|
1328
|
+
}
|
|
1329
|
+
return { ...observed, persisted: true };
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1262
1332
|
export function resetHerdrDeliveriesForTests() {
|
|
1263
1333
|
deliveries.clear();
|
|
1334
|
+
offlineDeliveries = new WeakMap();
|
|
1264
1335
|
}
|
|
1265
1336
|
|
|
1266
1337
|
function evictDeliveries() {
|
|
@@ -1280,12 +1351,12 @@ function stateChangeSeq(value) {
|
|
|
1280
1351
|
return Number.isSafeInteger(seq) && seq >= 0 ? seq : undefined;
|
|
1281
1352
|
}
|
|
1282
1353
|
|
|
1283
|
-
function createDelivery(role, prompt, pre, seqBefore) {
|
|
1284
|
-
evictDeliveries();
|
|
1354
|
+
function createDelivery(role, prompt, pre, seqBefore, options = {}) {
|
|
1355
|
+
if (!options.offlinePersistence) evictDeliveries();
|
|
1285
1356
|
const createdAt = Date.now();
|
|
1286
1357
|
const seq = (deliverySeq += 1);
|
|
1287
1358
|
const digest = createHash("sha256").update(`${role}\u0000${createdAt}\u0000${seq}`).digest("hex");
|
|
1288
|
-
const deliveryId = `dlv-${digest.slice(0, 16)}-${createdAt.toString(36)}`;
|
|
1359
|
+
const deliveryId = options.offlineDeliveryId ?? `dlv-${digest.slice(0, 16)}-${createdAt.toString(36)}`;
|
|
1289
1360
|
const sentPrompt = promptWithReportRequirement(role, prompt, deliveryId);
|
|
1290
1361
|
const record = {
|
|
1291
1362
|
deliveryId,
|
|
@@ -1304,7 +1375,7 @@ function createDelivery(role, prompt, pre, seqBefore) {
|
|
|
1304
1375
|
code: undefined,
|
|
1305
1376
|
reason: undefined,
|
|
1306
1377
|
};
|
|
1307
|
-
|
|
1378
|
+
deliveryRecords(options).set(record.deliveryId, record);
|
|
1308
1379
|
return record;
|
|
1309
1380
|
}
|
|
1310
1381
|
|
|
@@ -1370,7 +1441,7 @@ async function deliverPrompt(operation, request, context, options, signal, repos
|
|
|
1370
1441
|
// unconfirmed returns the existing delivery instead of re-handing off.
|
|
1371
1442
|
// After the window, or once the prior delivery is confirmed
|
|
1372
1443
|
// (delivered/answered/failed), a repeat is a genuinely new delivery.
|
|
1373
|
-
const duplicate = findUnconfirmedDelivery(role, request.prompt);
|
|
1444
|
+
const duplicate = options.offlinePersistence ? undefined : findUnconfirmedDelivery(role, request.prompt);
|
|
1374
1445
|
if (duplicate) {
|
|
1375
1446
|
if (duplicate.state === "queued") {
|
|
1376
1447
|
return {
|
|
@@ -1419,7 +1490,11 @@ async function deliverPrompt(operation, request, context, options, signal, repos
|
|
|
1419
1490
|
} catch {
|
|
1420
1491
|
pre = undefined;
|
|
1421
1492
|
}
|
|
1422
|
-
record = createDelivery(role, request.prompt, pre, stateChangeSeq(current));
|
|
1493
|
+
record = createDelivery(role, request.prompt, pre, stateChangeSeq(current), options);
|
|
1494
|
+
if (options.offlinePersistence) {
|
|
1495
|
+
const latest = await options.offlinePersistence.get("delivery", record.deliveryId);
|
|
1496
|
+
if (latest?.state !== "queued") throw communicationError("delivery_held", "persisted delivery is held; no handoff started");
|
|
1497
|
+
}
|
|
1423
1498
|
// Handoff: `agent prompt` without --wait returns as soon as the CLI
|
|
1424
1499
|
// accepts the brief. The acceptance window is internal
|
|
1425
1500
|
// (COMMAND_TIMEOUT_MS); timeoutMs never schedules a model round-trip.
|
|
@@ -1602,7 +1677,7 @@ function regionBody(text, role, region, correlationLine) {
|
|
|
1602
1677
|
}
|
|
1603
1678
|
|
|
1604
1679
|
async function queryDelivery(request, context, options, signal, repositories) {
|
|
1605
|
-
const record = typeof request.deliveryId === "string" ?
|
|
1680
|
+
const record = typeof request.deliveryId === "string" ? deliveryRecords(options).get(request.deliveryId) : undefined;
|
|
1606
1681
|
if (!record) {
|
|
1607
1682
|
return deliveryRefusal("delivery", communicationError("delivery_unknown", "no live delivery record is known for this deliveryId (bounded, in-memory)"));
|
|
1608
1683
|
}
|
|
@@ -1704,6 +1779,36 @@ async function queryDelivery(request, context, options, signal, repositories) {
|
|
|
1704
1779
|
// Legacy blocking exchange (prompt → wait → provenanced report read). It is
|
|
1705
1780
|
// no longer reachable from the tool surface; the dispatch journey keeps its
|
|
1706
1781
|
// single-exchange semantics through this entry point unchanged.
|
|
1782
|
+
export async function inspectHerdrJourneyMarker(role, requestId, context, options = {}, signal) {
|
|
1783
|
+
requireRole(role);
|
|
1784
|
+
if (typeof requestId !== "string" || !/^[a-zA-Z0-9_-]{1,100}:[1-9][0-9]{0,2}$/.test(requestId)) {
|
|
1785
|
+
throw communicationError("journey-id-invalid", "bounded journey request ID required", "denied");
|
|
1786
|
+
}
|
|
1787
|
+
const repositories = trustedRepositories(expectedRepository(context));
|
|
1788
|
+
const current = await invokeHerdr("get", { action: "get", role }, context, options, signal);
|
|
1789
|
+
publicAgentObservation(extractAgent(current, "agent_info"), role, repositories);
|
|
1790
|
+
const history = readText(await invokeHerdr("read", { action: "read", role, readLines: MAX_REPORT_READ_LINES }, context, options, signal));
|
|
1791
|
+
// Absence is never evidence that an asynchronous pane send did not land.
|
|
1792
|
+
const lines = history.split("\n");
|
|
1793
|
+
const tag = `[journey:${requestId}]`;
|
|
1794
|
+
const occurrences = lines.filter((line) => line.trim() === tag).length;
|
|
1795
|
+
if (occurrences !== 1) return { present: false };
|
|
1796
|
+
const from = history.indexOf(tag) + tag.length;
|
|
1797
|
+
const tail = history.slice(from);
|
|
1798
|
+
// One report only, with no later journey prompt. An unrelated or ambiguous
|
|
1799
|
+
// pane exchange is not attributable merely because it is the latest text.
|
|
1800
|
+
if (/^\[journey:[^\]]+\]$/m.test(tail)) return { present: true };
|
|
1801
|
+
const markers = reportMarkersForRole(role);
|
|
1802
|
+
const relevant = allMarkerOccurrences(tail, true, markers)
|
|
1803
|
+
.filter((item) => (item.marker === markers.open || item.marker === markers.close)
|
|
1804
|
+
&& !isPromptContractMarker(history, { index: item.index + from, end: item.end + from }, markers));
|
|
1805
|
+
if (relevant.length !== 2 || relevant[0].marker !== markers.open || relevant[1].marker !== markers.close) {
|
|
1806
|
+
return { present: true };
|
|
1807
|
+
}
|
|
1808
|
+
try { return { present: true, report: extractReportFromSegment(history, role, from) }; }
|
|
1809
|
+
catch { return { present: true }; }
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1707
1812
|
export async function executeHerdrPromptExchange(params, context, options = {}, signal) {
|
|
1708
1813
|
let request;
|
|
1709
1814
|
const operation = "prompt";
|
|
@@ -1802,6 +1907,10 @@ export async function executeHerdrCommunication(params, context, options = {}, s
|
|
|
1802
1907
|
try {
|
|
1803
1908
|
request = validateParams(params);
|
|
1804
1909
|
operation = request.action;
|
|
1910
|
+
requireOfflinePersistence(options);
|
|
1911
|
+
if (options.offlinePersistence && !["prompt", "submit", "delivery"].includes(operation)) {
|
|
1912
|
+
throw communicationError("offline_delivery_required", "offline persistence requires a delivery-bound operation; role-keyed fallback is refused", "denied");
|
|
1913
|
+
}
|
|
1805
1914
|
const repository = expectedRepository(context);
|
|
1806
1915
|
const repositories = trustedRepositories(repository);
|
|
1807
1916
|
if (operation === "list") {
|
|
@@ -1818,11 +1927,16 @@ export async function executeHerdrCommunication(params, context, options = {}, s
|
|
|
1818
1927
|
// return an explicit receipt immediately. No model round-trip happens
|
|
1819
1928
|
// on this path; settlement is observed through the `delivery` action,
|
|
1820
1929
|
// get, wait, and read.
|
|
1821
|
-
return
|
|
1930
|
+
return options.offlinePersistence
|
|
1931
|
+
? await deliverPersistedPrompt(operation, request, context, options, signal, repositories)
|
|
1932
|
+
: await deliverPrompt(operation, request, context, options, signal, repositories);
|
|
1822
1933
|
}
|
|
1823
1934
|
if (operation === "delivery") {
|
|
1824
|
-
//
|
|
1825
|
-
|
|
1935
|
+
// Non-authorizing observation. Offline mode may persist proof or an
|
|
1936
|
+
// attribution-loss hold, but never sends; default mode is unchanged.
|
|
1937
|
+
return options.offlinePersistence
|
|
1938
|
+
? await queryPersistedDelivery(request, context, options, signal, repositories)
|
|
1939
|
+
: await queryDelivery(request, context, options, signal, repositories);
|
|
1826
1940
|
}
|
|
1827
1941
|
if (operation === "wait") {
|
|
1828
1942
|
const raw = await invokeHerdr(operation, request, context, options, signal);
|