@agentcomms/events-daemon 0.26.2 → 0.27.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
@@ -24,8 +24,12 @@ agent-events run # in a terminal you keep open: the owner of
24
24
  ## How it runs
25
25
 
26
26
  `agent-events run` starts the **foreground owner**. It owns the event database while that terminal runs, and stops
27
- cleanly on `agent-events stop` or when the terminal closes. There is no background service or autostart in this
28
- release; the desktop app will supervise it later. Its state lives in an owner-only directory. A state directory so
27
+ cleanly on `agent-events stop` or when the terminal closes. A clean stop writes `last-stop.json` beside the
28
+ database, with the owner's PID, the time, and whether it was asked to stop or got a signal, so a supervisor can tell
29
+ it from a crash. From 0.27.0 the desktop app can
30
+ run it for you: it starts it in the background, restarts it after a crash and keeps it running after the app quits
31
+ (see [the desktop app](../../README.md#the-desktop-app)). There is still no OS service of its own (launchd, systemd
32
+ or a Windows service). Its state lives in an owner-only directory. A state directory so
29
33
  deep that its control socket's path would pass the system limit (103 bytes on macOS, 107 on Linux) is refused, with
30
34
  a hint to pin a shorter one. `agent-events --version` (or `-V`) prints the installed daemon version; a subcommand's
31
35
  `--version <number>` continues to select an immutable rule, target, subscriber or judge version.
@@ -852,7 +852,7 @@ async function removeTarget(targetId, options = {}) {
852
852
  //#endregion
853
853
  //#region src/version.ts
854
854
  /** The package version, read from package.json at build time. */
855
- const VERSION = "0.26.2";
855
+ const VERSION = "0.27.0";
856
856
  //#endregion
857
857
  //#region src/mcp/server.ts
858
858
  function reply(data) {
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as addSubscriber, $t as isControlHello, A as normaliseSourceOptions, At as updateJudge, B as canonicalJudgeKindEnablement, Bt as deliveriesList, C as normaliseActivationDocument, Ct as judgeKindsList, D as normaliseGmailSourceOptions, Dt as removeJudge, E as classifySourceOptionChange, Et as judgesList, F as assertCreatableLayaJudge, Ft as doctor, G as registerLayaEnablementInputs, Gt as catalogueShow, H as layaEnablementInputsFor, Ht as heldList, I as assertLayaJudgeKindAvailable, It as ACTIVATION_FAILURE, J as addTarget, Jt as probeControl, K as createEventsMcpServer, Kt as approvalView, L as assertLayaRuleJudgeOffered, Lt as isActivationFailureCode, M as APPROVED_TYPESAFE_MODELS, Mt as assertDoctorReportV1, N as JUDGE_BUDGET_ID, Nt as assertDoctorReportV2, O as normaliseResendSourceOptions, Ot as removeJudgeModel, P as JUDGE_KIND_DEFINITIONS, Pt as assertDoctorReportV3, Q as targetTest, Qt as encodeControlFrame, R as canonicalJudge, Rt as disableAll, S as disclosureBindingFor, St as enableJudgeKind, T as sseDeliveryTarget, Tt as judgeTest, U as layaJudgeKindDefinitionFor, Ut as retryDelivery, V as judgeKindDefinition, Vt as dropDelivery, W as layaJudgeTermsFor, Wt as catalogueList, X as targetsList, Xt as ControlFrameReader, Y as removeTarget$1, Yt as CONTROL_PROTOCOL_VERSIONS, Z as updateTarget, Zt as controlFailure, _ as isOwnerControlWireOperation, _t as pause, an as readInstance, at as loadSqlite, b as canonicalSubscriber, bt as budgetShow, cn as assertControlSupported, ct as createRule$1, d as B3_SECRET_TERMINAL_ORIGIN, dn as verifyControlSocket, dt as removeRule, en as isControlRequest, et as removeSubscriber, f as isB3ControlOperation, fn as verifyPrivateSocketDirectory, ft as ruleShow$1, g as OWNER_CONTROL_WIRES, gn as eventPaths, gt as ruleTestRetained, h as layaJudgePreviewFor, hn as ensureOwnerOnlyFile, ht as ruleTest, in as processIsLive, it as status, j as normaliseWhatsAppSourceOptions, jt as enableAll, k as normaliseSlackSourceOptions, kt as updateBudget, ln as assertSocketPathFits, lt as disableRule$1, m as renderB3ApprovalPreviewV1, mn as ensureEventSocketDirectory, mt as updateRule, nn as mayRecoverStaleInstance, nt as updateSubscriber, on as removeInstance, ot as sourceShow$1, p as isB3SecretOperation, pn as ensureEventPaths, pt as rulesList, q as VERSION, qt as EventControlClient, rn as newInstanceRecord, rt as stop, sn as writeInstance, st as sourcesList, tn as negotiateVersion, tt as subscribersList, un as controlEndpoint, ut as enableRule, v as activationDocumentDigest, vt as resume, w as canonicalSseSubscriber, wt as judgeModelStatus, x as canonicalTarget, xt as disableJudgeKind, y as canonicalFullRuleDocument, yt as addJudge, z as canonicalJudgeBudget, zt as decideHeld } from "./b3-contract-BSQ-vU21.mjs";
2
+ import { $ as addSubscriber, $t as isControlHello, A as normaliseSourceOptions, At as updateJudge, B as canonicalJudgeKindEnablement, Bt as deliveriesList, C as normaliseActivationDocument, Ct as judgeKindsList, D as normaliseGmailSourceOptions, Dt as removeJudge, E as classifySourceOptionChange, Et as judgesList, F as assertCreatableLayaJudge, Ft as doctor, G as registerLayaEnablementInputs, Gt as catalogueShow, H as layaEnablementInputsFor, Ht as heldList, I as assertLayaJudgeKindAvailable, It as ACTIVATION_FAILURE, J as addTarget, Jt as probeControl, K as createEventsMcpServer, Kt as approvalView, L as assertLayaRuleJudgeOffered, Lt as isActivationFailureCode, M as APPROVED_TYPESAFE_MODELS, Mt as assertDoctorReportV1, N as JUDGE_BUDGET_ID, Nt as assertDoctorReportV2, O as normaliseResendSourceOptions, Ot as removeJudgeModel, P as JUDGE_KIND_DEFINITIONS, Pt as assertDoctorReportV3, Q as targetTest, Qt as encodeControlFrame, R as canonicalJudge, Rt as disableAll, S as disclosureBindingFor, St as enableJudgeKind, T as sseDeliveryTarget, Tt as judgeTest, U as layaJudgeKindDefinitionFor, Ut as retryDelivery, V as judgeKindDefinition, Vt as dropDelivery, W as layaJudgeTermsFor, Wt as catalogueList, X as targetsList, Xt as ControlFrameReader, Y as removeTarget$1, Yt as CONTROL_PROTOCOL_VERSIONS, Z as updateTarget, Zt as controlFailure, _ as isOwnerControlWireOperation, _t as pause, an as readInstance, at as loadSqlite, b as canonicalSubscriber, bt as budgetShow, cn as assertControlSupported, ct as createRule$1, d as B3_SECRET_TERMINAL_ORIGIN, dn as verifyControlSocket, dt as removeRule, en as isControlRequest, et as removeSubscriber, f as isB3ControlOperation, fn as verifyPrivateSocketDirectory, ft as ruleShow$1, g as OWNER_CONTROL_WIRES, gn as eventPaths, gt as ruleTestRetained, h as layaJudgePreviewFor, hn as ensureOwnerOnlyFile, ht as ruleTest, in as processIsLive, it as status, j as normaliseWhatsAppSourceOptions, jt as enableAll, k as normaliseSlackSourceOptions, kt as updateBudget, ln as assertSocketPathFits, lt as disableRule$1, m as renderB3ApprovalPreviewV1, mn as ensureEventSocketDirectory, mt as updateRule, nn as mayRecoverStaleInstance, nt as updateSubscriber, on as removeInstance, ot as sourceShow$1, p as isB3SecretOperation, pn as ensureEventPaths, pt as rulesList, q as VERSION, qt as EventControlClient, rn as newInstanceRecord, rt as stop, sn as writeInstance, st as sourcesList, tn as negotiateVersion, tt as subscribersList, un as controlEndpoint, ut as enableRule, v as activationDocumentDigest, vt as resume, w as canonicalSseSubscriber, wt as judgeModelStatus, x as canonicalTarget, xt as disableJudgeKind, y as canonicalFullRuleDocument, yt as addJudge, z as canonicalJudgeBudget, zt as decideHeld } from "./b3-contract-DIasFAno.mjs";
3
3
  import { a as createLayaWorkerBoundary, d as encodeWorkerFrame, h as isLayaTemplateId, l as WorkerFrameParser, u as createWorkerRequestId, v as installErrorSink } from "./worker-boundary-probe-CFN6EsyK.mjs";
4
4
  import { _ as JUDGE_KIND_TYPESAFE, c as validateLocalEndpoint, d as assertApprovedAddressSet, f as parseIpLiteral, h as JUDGE_KIND_LAYA, i as webhookDeliveryTarget, l as AddressPolicyError, m as JUDGE_KINDS, n as canonicalWebhookTarget, p as EventDomainError, r as secretWebhookUrlDescriptor, t as canonicalSecretWebhookUrl, u as assertAddressAllowed, v as assertJudgeKindEnabled, y as isJudgeKind } from "./webhook-target-EzLIFpIY.mjs";
5
5
  import { c as migrateEventSecrets, i as RecordStorageError, l as openEventSecretStore, n as LayaModelRepository, o as WriterQuiescer, s as withEventWriterLease, t as EventRecordCipher } from "./records-BRl5wEbC.mjs";
@@ -24210,19 +24210,58 @@ async function startOwnerWithLock(options, stateDir, paths, lock, started, onDat
24210
24210
  }
24211
24211
  /** Runs the owner until a local stop request or a terminal signal closes it cleanly. */
24212
24212
  async function runEventOwner(options = {}) {
24213
- const owner = await startEventOwner(options);
24213
+ const stateDir = options.stateDir ?? resolvePaths().stateDir;
24214
+ const signals = options.signals ?? process;
24215
+ const owner = await startEventOwner({
24216
+ ...options,
24217
+ stateDir
24218
+ });
24219
+ let reason = "request";
24214
24220
  const stop = () => {
24221
+ reason = "signal";
24215
24222
  owner.stop();
24216
24223
  };
24217
- process.once("SIGINT", stop);
24218
- process.once("SIGTERM", stop);
24224
+ signals.once("SIGINT", stop);
24225
+ signals.once("SIGTERM", stop);
24219
24226
  try {
24220
24227
  await owner.stopped;
24221
24228
  } finally {
24222
- process.off("SIGINT", stop);
24223
- process.off("SIGTERM", stop);
24229
+ signals.off("SIGINT", stop);
24230
+ signals.off("SIGTERM", stop);
24224
24231
  await owner.stop();
24225
24232
  }
24233
+ await writeLastStop(eventPaths(stateDir), reason);
24234
+ }
24235
+ const LAST_STOP_FILE = "last-stop.json";
24236
+ /**
24237
+ * The clean-stop marker (desktop 0.27.0, P2): `{"version":1,"pid":…,"at":"<ISO 8601>","reason":"request"|"signal"}`
24238
+ * beside the database. A supervisor that no longer has this process as its child reads it to tell a stop from a crash:
24239
+ * a marker for the service's PID, newer than its start, with reason `request`, means the person stopped it; reason
24240
+ * `signal` — a logout, a shutdown, a kill — is not their decision, and the desktop app restarts it as after a crash.
24241
+ * Owner-only like the instance record, and written atomically, so a reader sees the previous marker or this one, never
24242
+ * a part of either.
24243
+ */
24244
+ async function writeLastStop(paths, reason) {
24245
+ const target = join(paths.root, LAST_STOP_FILE);
24246
+ const temporary = join(paths.root, `${LAST_STOP_FILE}.${randomBytes(8).toString("hex")}.tmp`);
24247
+ const marker = {
24248
+ version: 1,
24249
+ pid: process.pid,
24250
+ at: (/* @__PURE__ */ new Date()).toISOString(),
24251
+ reason
24252
+ };
24253
+ try {
24254
+ await writeFile(temporary, `${JSON.stringify(marker)}\n`, {
24255
+ encoding: "utf8",
24256
+ mode: 384,
24257
+ flag: "wx"
24258
+ });
24259
+ await chmod(temporary, 384);
24260
+ await rename(temporary, target);
24261
+ } catch (error) {
24262
+ await rm(temporary, { force: true });
24263
+ throw error;
24264
+ }
24226
24265
  }
24227
24266
  async function handleControl(owner, lifecycle, database, activations, dispatcher, sourceRegistry, writerQuiescer, request, b3OwnerService, doctorReport, connectedAccounts = async () => []) {
24228
24267
  if (!isOwnerControlWireOperation(request.operation)) throw new CommsError("USAGE", "the local event control operation is not recognised");
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { t as B3_APPROVAL_VIEW_VARIANTS, n as B3_CAPABILITIES, r as B3_CONTROL_CONTRACT, i as B3_CONTROL_ERROR_CODES, a as B3_CONTROL_V1_OPERATION_SPECS, o as B3_CONTROL_V1_RESULT_OPERATIONS, s as B3_CONTROL_V1_SCHEMA_VERSION, c as B3_CONTROL_V1_SUCCESSOR_REQUIREMENT, l as B3_DESKTOP_CONTROL_OPERATIONS, u as B3_JUDGE_UNAVAILABLE_VARIANTS, d as B3_SECRET_TERMINAL_ORIGIN, K as createEventsMcpServer, m as renderB3ApprovalPreviewV1, it as status } from "./b3-contract-BSQ-vU21.mjs";
1
+ export { t as B3_APPROVAL_VIEW_VARIANTS, n as B3_CAPABILITIES, r as B3_CONTROL_CONTRACT, i as B3_CONTROL_ERROR_CODES, a as B3_CONTROL_V1_OPERATION_SPECS, o as B3_CONTROL_V1_RESULT_OPERATIONS, s as B3_CONTROL_V1_SCHEMA_VERSION, c as B3_CONTROL_V1_SUCCESSOR_REQUIREMENT, l as B3_DESKTOP_CONTROL_OPERATIONS, u as B3_JUDGE_UNAVAILABLE_VARIANTS, d as B3_SECRET_TERMINAL_ORIGIN, K as createEventsMcpServer, m as renderB3ApprovalPreviewV1, it as status } from "./b3-contract-DIasFAno.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcomms/events-daemon",
3
- "version": "0.26.2",
3
+ "version": "0.27.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",
@@ -37,12 +37,12 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@agentcomms/core": "0.26.2",
41
- "@agentcomms/events": "0.26.2",
42
- "@agentcomms/gmail": "0.26.2",
43
- "@agentcomms/whatsapp": "0.26.2",
44
- "@agentcomms/slack": "0.26.2",
45
- "@agentcomms/resend": "0.26.2"
40
+ "@agentcomms/core": "0.27.0",
41
+ "@agentcomms/events": "0.27.0",
42
+ "@agentcomms/gmail": "0.27.0",
43
+ "@agentcomms/resend": "0.27.0",
44
+ "@agentcomms/slack": "0.27.0",
45
+ "@agentcomms/whatsapp": "0.27.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@modelcontextprotocol/client": "2.3.1",
@@ -73,5 +73,5 @@
73
73
  "typecheck": "tsc -p tsconfig.json",
74
74
  "test": "node --import ../../test/helpers/loopback-seal-preload.mjs --experimental-strip-types --disable-warning=ExperimentalWarning --test \"test/**/*.test.ts\" test/laya-runtime-package.test.mjs"
75
75
  },
76
- "gitHead": "c3fbb731e23401ea56862349d3c1e596be53ed11"
76
+ "gitHead": "9cb31ae29511a6b9424464601540c1ce9584ecea"
77
77
  }