@agentcomms/events-daemon 0.18.1 → 0.19.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/README.md CHANGED
@@ -57,6 +57,11 @@ agent-events dryrun show <record-id>
57
57
  Switch collection on before approving the rule: a pending target can be tested only while collection is on. If a test
58
58
  cannot run, the approval says why and still asks for its challenge.
59
59
 
60
+ An approval that `rule enable` or `enable-all` prints lasts 30 minutes. If it runs out, or is revoked, before you
61
+ approve it, nothing is turned on. On its next tick, or when it next starts, the service cancels the activation that
62
+ was waiting for it, and `status` stops counting it as pending. Run `rule enable` again for a new approval. An update
63
+ that lapsed this way no longer blocks the rule's next version.
64
+
60
65
  `rule.json`:
61
66
 
62
67
  ```json
@@ -832,7 +832,7 @@ async function removeTarget(targetId, options = {}) {
832
832
  //#endregion
833
833
  //#region src/version.ts
834
834
  /** The package version, read from package.json at build time. */
835
- const VERSION = "0.18.1";
835
+ const VERSION = "0.19.0";
836
836
  //#endregion
837
837
  //#region src/mcp/server.ts
838
838
  function reply(data) {
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as sourcesList, $t as assertControlSupported, A as normaliseWhatsAppSourceOptions, At as decideHeld, B as addTarget, Bt as CONTROL_PROTOCOL_VERSIONS, C as canonicalSseSubscriber, Ct as enableAll, D as normaliseResendSourceOptions, Dt as ACTIVATION_FAILURE, E as normaliseGmailSourceOptions, Et as doctor, F as canonicalJudgeBudget, Ft as catalogueList, G as addSubscriber, Gt as isControlRequest, H as targetsList, Ht as controlFailure, I as canonicalJudgeKindEnablement, It as catalogueShow, J as updateSubscriber, Jt as newInstanceRecord, K as removeSubscriber, Kt as negotiateVersion, L as judgeKindDefinition, Lt as approvalView, M as JUDGE_BUDGET_ID, Mt as dropDelivery, N as JUDGE_KIND_DEFINITIONS, Nt as heldList, O as normaliseSlackSourceOptions, Ot as isActivationFailureCode, P as canonicalJudge, Pt as retryDelivery, Q as sourceShow$1, Qt as writeInstance, R as createEventsMcpServer, Rt as EventControlClient, S as normaliseActivationDocument, St as updateJudge, T as classifySourceOptionChange, Tt as assertDoctorReportV2, U as updateTarget, Ut as encodeControlFrame, V as removeTarget$1, Vt as ControlFrameReader, W as targetTest, Wt as isControlHello, X as status, Xt as readInstance, Y as stop, Yt as processIsLive, Z as loadSqlite, Zt as removeInstance, _ as activationDocumentDigest, _t as judgeTest, an as ensureEventSocketDirectory, at as rulesList, b as canonicalTarget, bt as removeJudgeModel, cn as installErrorSink, ct as ruleTestRetained, d as B3_SECRET_TERMINAL_ORIGIN, dt as addJudge, en as assertSocketPathFits, et as createRule$1, f as isB3ControlOperation, ft as budgetShow, g as isOwnerControlWireOperation, gt as judgeModelStatus, h as OWNER_CONTROL_WIRES, ht as judgeKindsList, in as ensureEventPaths, it as ruleShow$1, j as APPROVED_TYPESAFE_MODELS, jt as deliveriesList, k as normaliseSourceOptions, kt as disableAll, lt as pause, m as renderB3ApprovalPreviewV1, mt as enableJudgeKind, nn as verifyControlSocket, nt as enableRule, on as ensureOwnerOnlyFile, ot as updateRule, p as isB3SecretOperation, pt as disableJudgeKind, q as subscribersList, qt as mayRecoverStaleInstance, rn as verifyPrivateSocketDirectory, rt as removeRule, sn as eventPaths, st as ruleTest, tn as controlEndpoint, tt as disableRule$1, ut as resume, v as canonicalFullRuleDocument, vt as judgesList, w as sseDeliveryTarget, wt as assertDoctorReportV1, x as disclosureBindingFor, xt as updateBudget, y as canonicalSubscriber, yt as removeJudge, z as VERSION, zt as probeControl } from "./b3-contract-BZIj-LWV.mjs";
2
+ import { $ as sourcesList, $t as assertControlSupported, A as normaliseWhatsAppSourceOptions, At as decideHeld, B as addTarget, Bt as CONTROL_PROTOCOL_VERSIONS, C as canonicalSseSubscriber, Ct as enableAll, D as normaliseResendSourceOptions, Dt as ACTIVATION_FAILURE, E as normaliseGmailSourceOptions, Et as doctor, F as canonicalJudgeBudget, Ft as catalogueList, G as addSubscriber, Gt as isControlRequest, H as targetsList, Ht as controlFailure, I as canonicalJudgeKindEnablement, It as catalogueShow, J as updateSubscriber, Jt as newInstanceRecord, K as removeSubscriber, Kt as negotiateVersion, L as judgeKindDefinition, Lt as approvalView, M as JUDGE_BUDGET_ID, Mt as dropDelivery, N as JUDGE_KIND_DEFINITIONS, Nt as heldList, O as normaliseSlackSourceOptions, Ot as isActivationFailureCode, P as canonicalJudge, Pt as retryDelivery, Q as sourceShow$1, Qt as writeInstance, R as createEventsMcpServer, Rt as EventControlClient, S as normaliseActivationDocument, St as updateJudge, T as classifySourceOptionChange, Tt as assertDoctorReportV2, U as updateTarget, Ut as encodeControlFrame, V as removeTarget$1, Vt as ControlFrameReader, W as targetTest, Wt as isControlHello, X as status, Xt as readInstance, Y as stop, Yt as processIsLive, Z as loadSqlite, Zt as removeInstance, _ as activationDocumentDigest, _t as judgeTest, an as ensureEventSocketDirectory, at as rulesList, b as canonicalTarget, bt as removeJudgeModel, cn as installErrorSink, ct as ruleTestRetained, d as B3_SECRET_TERMINAL_ORIGIN, dt as addJudge, en as assertSocketPathFits, et as createRule$1, f as isB3ControlOperation, ft as budgetShow, g as isOwnerControlWireOperation, gt as judgeModelStatus, h as OWNER_CONTROL_WIRES, ht as judgeKindsList, in as ensureEventPaths, it as ruleShow$1, j as APPROVED_TYPESAFE_MODELS, jt as deliveriesList, k as normaliseSourceOptions, kt as disableAll, lt as pause, m as renderB3ApprovalPreviewV1, mt as enableJudgeKind, nn as verifyControlSocket, nt as enableRule, on as ensureOwnerOnlyFile, ot as updateRule, p as isB3SecretOperation, pt as disableJudgeKind, q as subscribersList, qt as mayRecoverStaleInstance, rn as verifyPrivateSocketDirectory, rt as removeRule, sn as eventPaths, st as ruleTest, tn as controlEndpoint, tt as disableRule$1, ut as resume, v as canonicalFullRuleDocument, vt as judgesList, w as sseDeliveryTarget, wt as assertDoctorReportV1, x as disclosureBindingFor, xt as updateBudget, y as canonicalSubscriber, yt as removeJudge, z as VERSION, zt as probeControl } from "./b3-contract-9xDk86Z-.mjs";
3
3
  import { a as EventDomainError, d as isJudgeKind, f as validateLocalEndpoint, g as parseIpLiteral, h as assertApprovedAddressSet, i as webhookDeliveryTarget, l as JUDGE_KIND_TYPESAFE, m as assertAddressAllowed, n as canonicalWebhookTarget, o as JUDGE_KINDS, p as AddressPolicyError, r as secretWebhookUrlDescriptor, s as JUDGE_KIND_LAYA, t as canonicalSecretWebhookUrl, u as assertJudgeKindEnabled } from "./webhook-target-DyDTwWhV.mjs";
4
4
  import { a as WriterQuiescer, c as openEventSecretStore, o as withEventWriterLease, r as RecordStorageError, s as migrateEventSecrets, t as EventRecordCipher } from "./records-DsUxYBwb.mjs";
5
5
  import process$1 from "node:process";
@@ -11935,6 +11935,7 @@ var ActivationRuntime = class {
11935
11935
  };
11936
11936
  }
11937
11937
  const oldId = `${input.ruleId}@${active.version}`;
11938
+ await this.#settleLapsedApprovals(oldId);
11938
11939
  if (this.#store.database.prepare("SELECT 1 AS present FROM activation_intents WHERE replacement_of_version = ? AND status IN ('pending', 'pending-completion')").get(oldId) !== void 0) throw new CommsError("TRANSIENT", "this rule already has a replacement completing", { details: { reason: "REPLACEMENT_PENDING" } });
11939
11940
  const live = await liveEventAccountIds(this.#config, parent.source.channel);
11940
11941
  const points = this.#unionReplacementPoints(parent, document.rule).filter((point) => point.ruleVersion !== parent.version || live.has(point.accountId) && this.#holdsActivePoint(parent.ruleId, parent.version, {
@@ -12154,6 +12155,7 @@ var ActivationRuntime = class {
12154
12155
  this.#cancel(intent.id, ACTIVATION_FAILURE.APPROVAL_ABSENT);
12155
12156
  continue;
12156
12157
  }
12158
+ if (this.#settleLapsedApproval(intent.id, intent.approval_id, record)) continue;
12157
12159
  if (record.record.state === "approved") {
12158
12160
  const binding = this.#settleOnDrift(intent);
12159
12161
  if (binding === null) continue;
@@ -12188,7 +12190,8 @@ var ActivationRuntime = class {
12188
12190
  }
12189
12191
  /**
12190
12192
  * A live owner retries only work that core has already marked used. Unlike startup recovery this never claims an
12191
- * approved disclosure and it always carries the immutable usedAt back through the ordinary completion path.
12193
+ * approved disclosure and it always carries the immutable usedAt back through the ordinary completion path. After
12194
+ * that claimed work, it settles every unclaimed intent whose approval lapsed unused, as startup recovery does.
12192
12195
  */
12193
12196
  async resumeClaimedCompletions() {
12194
12197
  const rows = this.#store.database.prepare("SELECT id, kind, document, digest, effect, replacement_of_version, status, approval_id, claimed_at, completion_deadline FROM activation_intents WHERE status = 'pending-completion' ORDER BY id").all();
@@ -12217,6 +12220,36 @@ var ActivationRuntime = class {
12217
12220
  throw error;
12218
12221
  }
12219
12222
  }
12223
+ await this.#settleLapsedApprovals();
12224
+ }
12225
+ /** Settles the unclaimed pending intents — of one replacement slot, or every one — whose approval lapsed unused. */
12226
+ async #settleLapsedApprovals(replacementOfVersion) {
12227
+ const rows = this.#store.database.prepare("SELECT id, approval_id, replacement_of_version FROM activation_intents WHERE status = 'pending' AND claimed_at IS NULL AND approval_id IS NOT NULL ORDER BY id").all();
12228
+ for (const row of rows) {
12229
+ if (replacementOfVersion !== void 0 && row.replacement_of_version !== replacementOfVersion) continue;
12230
+ this.#settleLapsedApproval(row.id, row.approval_id, await this.#approvals.get(row.approval_id));
12231
+ }
12232
+ }
12233
+ /**
12234
+ * CUE-491: a disclosure approval that core reads as expired or revoked can never be approved or claimed again, so
12235
+ * its unclaimed intent is cancelled (D2: expired, revoked and absent drop). Left pending, every pass would carry it
12236
+ * for good, and an update's would hold its rule's one replacement slot, refusing the next update as
12237
+ * REPLACEMENT_PENDING. Core's answer crossed an await: the write re-reads the intent under its transaction and
12238
+ * settles only the same unclaimed pending one. The failure code reuses APPROVAL_ABSENT — no usable approval
12239
+ * remains, as the claimed path already records for a non-used one — because the B3 control and doctor v1 schemas
12240
+ * that close the code set are pinned.
12241
+ */
12242
+ #settleLapsedApproval(intentId, approvalId, record) {
12243
+ if (record?.form !== "v2" || record.record.kind !== "disclosure") return false;
12244
+ if (record.record.state !== "expired" && record.record.state !== "revoked") return false;
12245
+ let settled = false;
12246
+ this.#store.immediate(() => {
12247
+ const latest = this.#store.database.prepare("SELECT status, approval_id, claimed_at FROM activation_intents WHERE id = ?").get(intentId);
12248
+ if (latest?.status !== "pending" || latest.claimed_at !== null || latest.approval_id !== approvalId) return;
12249
+ this.#cancel(intentId, ACTIVATION_FAILURE.APPROVAL_ABSENT);
12250
+ settled = true;
12251
+ });
12252
+ return settled;
12220
12253
  }
12221
12254
  /**
12222
12255
  * The live binding of a claimed intent, or null after settling it: a binding that no longer holds (its pointer or
@@ -17571,7 +17604,8 @@ var EventScheduler = class {
17571
17604
  internalDomains: inbox?.internalDomains ?? []
17572
17605
  }, input);
17573
17606
  } },
17574
- ...this.#hostedJudgeKeyFor === void 0 ? {} : { hostedJudgeKeyFor: this.#hostedJudgeKeyFor }
17607
+ ...this.#hostedJudgeKeyFor === void 0 ? {} : { hostedJudgeKeyFor: this.#hostedJudgeKeyFor },
17608
+ now: this.#now
17575
17609
  });
17576
17610
  const fence = async (rule) => {
17577
17611
  await assertDisclosable({
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { R as createEventsMcpServer, X as status, a as B3_CONTROL_V1_OPERATION_SPECS, c as B3_CONTROL_V1_SUCCESSOR_REQUIREMENT, d as B3_SECRET_TERMINAL_ORIGIN, i as B3_CONTROL_ERROR_CODES, l as B3_DESKTOP_CONTROL_OPERATIONS, m as renderB3ApprovalPreviewV1, n as B3_CAPABILITIES, o as B3_CONTROL_V1_RESULT_OPERATIONS, r as B3_CONTROL_CONTRACT, s as B3_CONTROL_V1_SCHEMA_VERSION, t as B3_APPROVAL_VIEW_VARIANTS, u as B3_JUDGE_UNAVAILABLE_VARIANTS } from "./b3-contract-BZIj-LWV.mjs";
1
+ import { R as createEventsMcpServer, X as status, a as B3_CONTROL_V1_OPERATION_SPECS, c as B3_CONTROL_V1_SUCCESSOR_REQUIREMENT, d as B3_SECRET_TERMINAL_ORIGIN, i as B3_CONTROL_ERROR_CODES, l as B3_DESKTOP_CONTROL_OPERATIONS, m as renderB3ApprovalPreviewV1, n as B3_CAPABILITIES, o as B3_CONTROL_V1_RESULT_OPERATIONS, r as B3_CONTROL_CONTRACT, s as B3_CONTROL_V1_SCHEMA_VERSION, t as B3_APPROVAL_VIEW_VARIANTS, u as B3_JUDGE_UNAVAILABLE_VARIANTS } from "./b3-contract-9xDk86Z-.mjs";
2
2
  export { B3_APPROVAL_VIEW_VARIANTS, B3_CAPABILITIES, B3_CONTROL_CONTRACT, B3_CONTROL_ERROR_CODES, B3_CONTROL_V1_OPERATION_SPECS, B3_CONTROL_V1_RESULT_OPERATIONS, B3_CONTROL_V1_SCHEMA_VERSION, B3_CONTROL_V1_SUCCESSOR_REQUIREMENT, B3_DESKTOP_CONTROL_OPERATIONS, B3_JUDGE_UNAVAILABLE_VARIANTS, B3_SECRET_TERMINAL_ORIGIN, createEventsMcpServer, renderB3ApprovalPreviewV1, status };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcomms/events-daemon",
3
- "version": "0.18.1",
3
+ "version": "0.19.0",
4
4
  "description": "The local event service for agent-communications: rules you approve deliver Gmail, Slack, Resend and WhatsApp events to a signed webhook, a local live stream or a dry-run log.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,12 +34,12 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@agentcomms/core": "0.18.1",
38
- "@agentcomms/gmail": "0.18.1",
39
- "@agentcomms/events": "0.18.1",
40
- "@agentcomms/whatsapp": "0.18.1",
41
- "@agentcomms/slack": "0.18.1",
42
- "@agentcomms/resend": "0.18.1"
37
+ "@agentcomms/events": "0.19.0",
38
+ "@agentcomms/core": "0.19.0",
39
+ "@agentcomms/gmail": "0.19.0",
40
+ "@agentcomms/resend": "0.19.0",
41
+ "@agentcomms/whatsapp": "0.19.0",
42
+ "@agentcomms/slack": "0.19.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@modelcontextprotocol/client": "2.3.1",
@@ -70,5 +70,5 @@
70
70
  "typecheck": "tsc -p tsconfig.json",
71
71
  "test": "node --import ../../test/helpers/loopback-seal-preload.mjs --experimental-strip-types --disable-warning=ExperimentalWarning --test \"test/**/*.test.ts\""
72
72
  },
73
- "gitHead": "fc398edc67287e411f8c5cb821f434220cb83aa5"
73
+ "gitHead": "29a7121620a9ef305a4260f193c40db1980312bd"
74
74
  }