@rubytech/create-sitedesk-code 0.1.550 → 0.1.552

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.
Files changed (128) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/agent-dispatch-rule/dist/index.d.ts +22 -8
  3. package/payload/platform/lib/agent-dispatch-rule/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/agent-dispatch-rule/dist/index.js +47 -13
  5. package/payload/platform/lib/agent-dispatch-rule/dist/index.js.map +1 -1
  6. package/payload/platform/lib/agent-dispatch-rule/src/__tests__/rule.test.ts +68 -9
  7. package/payload/platform/lib/agent-dispatch-rule/src/index.ts +60 -16
  8. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -3
  9. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +9 -0
  10. package/payload/platform/plugins/docs/references/admin-ui.md +2 -2
  11. package/payload/platform/plugins/scheduling/PLUGIN.md +22 -0
  12. package/payload/platform/plugins/scheduling/mcp/dist/index.js +107 -6
  13. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  14. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js +2 -2
  15. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js.map +1 -1
  16. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-freebusy.test.d.ts +2 -0
  17. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-freebusy.test.d.ts.map +1 -0
  18. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-freebusy.test.js +216 -0
  19. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-freebusy.test.js.map +1 -0
  20. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js +2 -2
  21. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js.map +1 -1
  22. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.d.ts +2 -0
  23. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.d.ts.map +1 -0
  24. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +128 -0
  25. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -0
  26. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.d.ts +2 -0
  27. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.d.ts.map +1 -0
  28. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +135 -0
  29. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -0
  30. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-audit.test.js +132 -0
  31. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-audit.test.js.map +1 -1
  32. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-freebusy.d.ts +86 -0
  33. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-freebusy.d.ts.map +1 -0
  34. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-freebusy.js +240 -0
  35. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-freebusy.js.map +1 -0
  36. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts.map +1 -1
  37. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js +21 -8
  38. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js.map +1 -1
  39. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +92 -0
  40. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -0
  41. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +193 -0
  42. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -0
  43. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +8 -1
  44. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts.map +1 -1
  45. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -1
  46. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +94 -1
  47. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
  48. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +299 -0
  49. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
  50. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.d.ts +2 -0
  51. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.d.ts.map +1 -0
  52. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js +146 -0
  53. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js.map +1 -0
  54. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +27 -0
  55. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  56. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +18 -0
  57. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  58. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +119 -64
  59. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  60. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-connector-busy-sync.test.js +84 -1
  61. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-connector-busy-sync.test.js.map +1 -1
  62. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.d.ts +2 -0
  63. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.d.ts.map +1 -0
  64. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +218 -0
  65. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -0
  66. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.d.ts +2 -0
  67. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.d.ts.map +1 -0
  68. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +291 -0
  69. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -0
  70. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.d.ts +26 -2
  71. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.d.ts.map +1 -1
  72. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.js +51 -2
  73. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.js.map +1 -1
  74. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +31 -0
  75. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
  76. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +44 -1
  77. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
  78. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts +3 -1
  79. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
  80. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +57 -3
  81. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
  82. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +148 -0
  83. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -0
  84. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +410 -0
  85. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -0
  86. package/payload/platform/plugins/scheduling/mcp/package.json +1 -0
  87. package/payload/platform/plugins/telegram/.claude-plugin/plugin.json +1 -1
  88. package/payload/platform/plugins/telegram/PLUGIN.md +6 -4
  89. package/payload/platform/plugins/telegram/mcp/dist/index.js +62 -38
  90. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
  91. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts +18 -5
  92. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts.map +1 -1
  93. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js +34 -6
  94. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js.map +1 -1
  95. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts +25 -8
  96. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts.map +1 -1
  97. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js +28 -16
  98. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js.map +1 -1
  99. package/payload/platform/plugins/telegram/mcp/dist/lib/agent-active.d.ts +12 -0
  100. package/payload/platform/plugins/telegram/mcp/dist/lib/agent-active.d.ts.map +1 -0
  101. package/payload/platform/plugins/telegram/mcp/dist/lib/agent-active.js +26 -0
  102. package/payload/platform/plugins/telegram/mcp/dist/lib/agent-active.js.map +1 -0
  103. package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts +16 -13
  104. package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts.map +1 -1
  105. package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js +19 -23
  106. package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js.map +1 -1
  107. package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts +9 -7
  108. package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts.map +1 -1
  109. package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js +11 -8
  110. package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js.map +1 -1
  111. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +4 -0
  112. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -1
  113. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +13 -3
  114. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -1
  115. package/payload/platform/plugins/telegram/references/setup-guide.md +16 -8
  116. package/payload/platform/plugins/telegram/skills/configure/SKILL.md +30 -32
  117. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  118. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  119. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  120. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +51 -4
  121. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
  122. package/payload/platform/services/claude-session-manager/dist/pty-census.js +60 -10
  123. package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
  124. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts +64 -1
  125. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -1
  126. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +189 -6
  127. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -1
  128. package/payload/server/server.js +510 -240
@@ -1,4 +1,8 @@
1
+ import { readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
1
3
  import { scheduleList } from "../tools/schedule-list.js";
4
+ import { readWatermarks } from "../tools/scheduling-gate.js";
5
+ import { resolveConnector } from "./connector-freebusy.js";
2
6
  /**
3
7
  * Task 2100 — the standing check for meeting visibility.
4
8
  *
@@ -30,4 +34,299 @@ export async function auditScheduleVisibility(session, accountId, list = schedul
30
34
  console.error(`[schedule-audit] account=${accountId} meetings=${meetings} listable=${listable} invisible=${invisible}`);
31
35
  return { meetings, listable, invisible };
32
36
  }
37
+ /** Neo4j integers arrive as `{low, high}` objects; normalise to a JS number. */
38
+ function num(raw) {
39
+ if (typeof raw === "number")
40
+ return raw;
41
+ if (raw && typeof raw.toNumber === "function") {
42
+ return raw.toNumber();
43
+ }
44
+ return Number(raw ?? 0);
45
+ }
46
+ /**
47
+ * Task 2378 — the gate stuck on false.
48
+ *
49
+ * This is the gate's no-event blind spot, and it is invisible by construction. A
50
+ * gate that answers `false` on every fire emits a skip every fire and looks
51
+ * healthy on every surface: the routine is `scheduled`, `nextRun` keeps
52
+ * advancing, the run records close clean, and no error is written anywhere. The
53
+ * only symptom is silence from a routine that was DESIGNED to be silent, which
54
+ * is why no fire-site line can report it and why it needs a standing check.
55
+ *
56
+ * Always-skipping means every trailing-24h `:RoutineRun` for that event closed
57
+ * `gated`, and there are at least 24 of them. Twenty-four is one day at hourly,
58
+ * the cadence the routine that produced this task held for 15 consecutive days.
59
+ * A genuinely quiet 24 hours does trip it: it WARNs, nothing acts on it, and
60
+ * that is the safe direction — the alternative never sees a permanently muted
61
+ * routine at all.
62
+ *
63
+ * `checked=0` is emitted every tick, including on an install with no gated
64
+ * routines. A check that goes quiet when healthy cannot be distinguished from
65
+ * one that has stopped running.
66
+ *
67
+ * Never throws (honours the sweep's contract).
68
+ */
69
+ export async function auditGateAlwaysSkipping(driver, localAccountIds, nowMs = Date.now()) {
70
+ if (localAccountIds.length === 0)
71
+ return;
72
+ const windowStart = new Date(nowMs - 24 * 60 * 60 * 1000).toISOString();
73
+ const session = driver.session();
74
+ try {
75
+ const res = await session.run(
76
+ // Scoped to `scheduled` gated events, the same predicate every sibling
77
+ // "this row is broken" audit uses: a suspended or cancelled routine is
78
+ // silent because someone asked it to be, and counting it would park this
79
+ // number above zero for ever and kill the alarm.
80
+ `MATCH (e:Event)
81
+ WHERE e.accountId IN $localAccountIds
82
+ AND e.eventStatus = 'scheduled'
83
+ AND e.gatePlugin IS NOT NULL
84
+ AND e.gateTool IS NOT NULL
85
+ OPTIONAL MATCH (r:RoutineRun)-[:RUN_OF]->(e)
86
+ WHERE r.startedAt >= $windowStart
87
+ RETURN e.eventId AS eventId, e.accountId AS accountId,
88
+ count(r) AS runs,
89
+ sum(CASE WHEN r.status = 'gated' THEN 1 ELSE 0 END) AS gatedRuns`, { localAccountIds, windowStart });
90
+ let checked = 0;
91
+ const offenders = [];
92
+ for (const rec of res.records) {
93
+ checked++;
94
+ const runs = num(rec.get("runs"));
95
+ const gatedRuns = num(rec.get("gatedRuns"));
96
+ if (runs >= 24 && gatedRuns === runs) {
97
+ offenders.push({
98
+ eventId: rec.get("eventId"),
99
+ accountId: rec.get("accountId"),
100
+ gatedRuns,
101
+ });
102
+ }
103
+ }
104
+ console.error(`[schedule-audit] op=gate-census checked=${checked} alwaysSkipping=${offenders.length} ` +
105
+ `ok=${offenders.length === 0}`);
106
+ for (const o of offenders) {
107
+ console.error(`[schedule-audit] op=gate-always-skipping eventId=${o.eventId.slice(0, 8)} ` +
108
+ `acct=${o.accountId.slice(0, 8)} gatedRuns=${o.gatedRuns} sinceHours=24`);
109
+ }
110
+ }
111
+ catch (err) {
112
+ console.error(`[schedule-audit] op=gate-census-error detail=${err instanceof Error ? err.message : String(err)}`);
113
+ }
114
+ finally {
115
+ try {
116
+ await session.close();
117
+ }
118
+ catch {
119
+ // ignore
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Task 2378 — the watermark that stopped advancing.
125
+ *
126
+ * The opposite failure to the one above, and just as quiet. Only the agent turn
127
+ * commits a watermark, at the end of a successful run. If those commits stop —
128
+ * a prompt edited back to its pre-gate wording, a turn that always dies before
129
+ * its last step — the gate keeps comparing against a frozen position, reports
130
+ * work on every fire, and the routine runs every time. There is no error, no
131
+ * missing line and no failed call; it simply reads as a busy week while the
132
+ * whole saving is gone.
133
+ *
134
+ * `op=commit` is emitted only on a successful commit, so its ABSENCE is the
135
+ * signal, and an absence is not greppable on its own. This is the greppable
136
+ * form of it. Together with the always-skipping check it bounds the same 24-hour
137
+ * window from opposite ends: one catches a gate that never passes, this one a
138
+ * gate that never stops passing.
139
+ *
140
+ * Only a routine that has actually fired is judged. A gate bound minutes ago has
141
+ * no commit yet and is not late.
142
+ *
143
+ * `acct=` lines are emitted every tick including when nothing is late. Never
144
+ * throws (honours the sweep's contract).
145
+ */
146
+ export async function auditGateWatermarkAge(driver, localAccountIds, platformRoot, nowMs = Date.now()) {
147
+ if (localAccountIds.length === 0)
148
+ return;
149
+ const session = driver.session();
150
+ try {
151
+ const res = await session.run(`MATCH (e:Event)
152
+ WHERE e.accountId IN $localAccountIds
153
+ AND e.eventStatus = 'scheduled'
154
+ AND e.gatePlugin IS NOT NULL
155
+ AND e.gateTool IS NOT NULL
156
+ AND e.lastTriggered IS NOT NULL
157
+ RETURN e.eventId AS eventId, e.accountId AS accountId`, { localAccountIds });
158
+ // Worst age per account, so one line per account answers "is any gate on
159
+ // this account running blind". Driven by localAccountIds below, not by the
160
+ // result rows: an account with no gated routines emits `-`, and skipping it
161
+ // would make "nothing to check" and "not looked at" the same silence.
162
+ const worst = new Map();
163
+ for (const rec of res.records) {
164
+ const eventId = rec.get("eventId");
165
+ const accountId = rec.get("accountId");
166
+ const marks = readWatermarks(eventId, platformRoot);
167
+ // A routine that has fired and never committed is maximally late, not
168
+ // exempt: never having committed is the state this check exists to find.
169
+ const ageHours = marks.lastCommitAt && !Number.isNaN(Date.parse(marks.lastCommitAt))
170
+ ? (nowMs - Date.parse(marks.lastCommitAt)) / 3_600_000
171
+ : Number.POSITIVE_INFINITY;
172
+ const current = worst.get(accountId);
173
+ if (current === undefined || ageHours > current) {
174
+ worst.set(accountId, ageHours);
175
+ }
176
+ }
177
+ for (const accountId of localAccountIds) {
178
+ const age = worst.get(accountId);
179
+ if (age === undefined) {
180
+ console.error(`[schedule-audit] op=gate-watermark-age acct=${accountId.slice(0, 8)} ` +
181
+ `lastCommitAgeHours=- ok=true`);
182
+ continue;
183
+ }
184
+ const ok = age <= 24;
185
+ console.error(`[schedule-audit] op=gate-watermark-age acct=${accountId.slice(0, 8)} ` +
186
+ `lastCommitAgeHours=${age === Number.POSITIVE_INFINITY ? "never" : Math.round(age)} ok=${ok}`);
187
+ }
188
+ }
189
+ catch (err) {
190
+ console.error(`[schedule-audit] op=gate-watermark-age-error detail=${err instanceof Error ? err.message : String(err)}`);
191
+ }
192
+ finally {
193
+ try {
194
+ await session.close();
195
+ }
196
+ catch {
197
+ // ignore
198
+ }
199
+ }
200
+ }
201
+ /**
202
+ * The next state for one account.
203
+ *
204
+ * The `none` instant survives consecutive `none` observations and is discarded
205
+ * the moment a connector returns, which is what makes `noneForHours` the length
206
+ * of the CURRENT run rather than a cumulative total. A recovery followed by a
207
+ * fresh revocation therefore starts counting again from zero, which is correct:
208
+ * the operator's exposure began when the calendar went away this time.
209
+ */
210
+ export function nextConnectorState(prev, connector, nowMs) {
211
+ if (connector !== "none")
212
+ return { connector, noneSinceMs: null };
213
+ return { connector: "none", noneSinceMs: prev?.noneSinceMs ?? nowMs };
214
+ }
215
+ /** Whole hours the account has resolved `none` without interruption. */
216
+ export function noneForHours(entry, nowMs) {
217
+ if (entry.noneSinceMs === null)
218
+ return 0;
219
+ return Math.max(0, Math.floor((nowMs - entry.noneSinceMs) / 3_600_000));
220
+ }
221
+ /** Read the persisted run lengths. An absent or corrupt file reads as empty,
222
+ * which restarts every account's clock — it can delay an alarm by 24 hours but
223
+ * never raises a false one. A corrupt file is reported, because it is the cause
224
+ * of a fleet-wide clock reset and that reset must carry its own explanation. */
225
+ function readConnectorState(path) {
226
+ let raw;
227
+ try {
228
+ raw = readFileSync(path, "utf-8");
229
+ }
230
+ catch {
231
+ return {}; // absent — the normal first-run case
232
+ }
233
+ try {
234
+ const parsed = JSON.parse(raw);
235
+ return parsed && typeof parsed === "object" ? parsed : {};
236
+ }
237
+ catch (err) {
238
+ console.error(`[schedule-audit] op=connector-state result=unreadable path=${path} ` +
239
+ `reason=${JSON.stringify(err.message)} impact=every-account-clock-reset`);
240
+ return {};
241
+ }
242
+ }
243
+ /** Written to a temp path and renamed, so a kill mid-write cannot leave
244
+ * truncated JSON that reads back as empty and resets every clock. */
245
+ function writeConnectorState(path, state) {
246
+ const tmp = `${path}.tmp`;
247
+ try {
248
+ writeFileSync(tmp, JSON.stringify(state));
249
+ renameSync(tmp, path);
250
+ }
251
+ catch (err) {
252
+ console.error(`[schedule-audit] op=connector-state result=write-failed path=${path} ` +
253
+ `reason=${JSON.stringify(err.message)} impact=none-run-length-never-grows`);
254
+ }
255
+ }
256
+ /**
257
+ * Task 2381 — the standing half of the connector-resolution signal.
258
+ *
259
+ * A revoked or expired authorisation makes every fire of the busy sync write an
260
+ * empty busy list. The action succeeds, the `:RoutineRun` closes clean, nothing
261
+ * errors, and the visible result is a booking page offering slots the operator is
262
+ * not free for. The per-fire `[connector-busy-sync] op=resolved connector=none`
263
+ * line IS emitted every fire, but one healthy-looking line among thousands is not
264
+ * a signal — this is what turns a persistent `none` into one.
265
+ *
266
+ * `ok=false` when an account has resolved `none` for more than 24 consecutive
267
+ * hours WHILE holding a scheduled busy-sync routine. An account with genuinely no
268
+ * calendar and no such routine reports a growing `noneForHours` and `ok=true`:
269
+ * nothing is scheduled to use a connector it does not have, so there is no
270
+ * exposure to report.
271
+ *
272
+ * The routine predicate matches the converted `action` form and the agent form
273
+ * that precedes it, so the audit is live from the day it ships rather than from
274
+ * the day the conversion lands.
275
+ *
276
+ * One line per local account per tick, including every healthy one. A check that
277
+ * goes quiet when healthy cannot be distinguished from one that has stopped
278
+ * running. Never throws (honours the sweep's contract).
279
+ */
280
+ export async function auditConnectorResolution(driver, localAccountIds, accountsDir, statePath, nowMs) {
281
+ if (localAccountIds.length === 0)
282
+ return;
283
+ const session = driver.session();
284
+ let withSyncRoutine;
285
+ try {
286
+ const res = await session.run(`MATCH (e:Event)
287
+ WHERE e.accountId IN $localAccountIds
288
+ AND e.eventStatus = 'scheduled'
289
+ AND ( e.actionTool = 'schedule-connector-busy-sync'
290
+ OR e.agentPrompt CONTAINS 'schedule-connector-busy-sync' )
291
+ RETURN DISTINCT e.accountId AS accountId`, { localAccountIds });
292
+ withSyncRoutine = new Set(res.records.map((r) => r.get("accountId")));
293
+ }
294
+ catch (err) {
295
+ console.error(`[schedule-audit] op=connector-resolution-error detail=${err instanceof Error ? err.message : String(err)}`);
296
+ return;
297
+ }
298
+ finally {
299
+ try {
300
+ await session.close();
301
+ }
302
+ catch {
303
+ // ignore
304
+ }
305
+ }
306
+ const state = readConnectorState(statePath);
307
+ // Driven by localAccountIds, not by the query result: an account resolving
308
+ // nothing returns no row, and skipping it would make "healthy" and "not looked
309
+ // at" the same silence on a multi-account box.
310
+ for (const accountId of localAccountIds) {
311
+ let connector;
312
+ try {
313
+ connector = resolveConnector(join(accountsDir, accountId)).connector;
314
+ }
315
+ catch (err) {
316
+ // detectCalendarConnectors throws when a connector directory exists but is
317
+ // unreadable. That is "the input is unknown", not "there is no connector",
318
+ // and reporting it as `none` would dress a real fault as the boring case.
319
+ console.error(`[schedule-audit] op=connector-resolution-error acct=${accountId.slice(0, 8)} ` +
320
+ `detail=${err instanceof Error ? err.message : String(err)}`);
321
+ continue;
322
+ }
323
+ const entry = nextConnectorState(state[accountId], connector, nowMs);
324
+ state[accountId] = entry;
325
+ const hours = noneForHours(entry, nowMs);
326
+ const ok = !(hours > 24 && withSyncRoutine.has(accountId));
327
+ console.error(`[schedule-audit] op=connector-resolution acct=${accountId.slice(0, 8)} ` +
328
+ `connector=${connector} noneForHours=${hours} ok=${ok}`);
329
+ }
330
+ writeConnectorState(statePath, state);
331
+ }
33
332
  //# sourceMappingURL=schedule-audit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-audit.js","sourceRoot":"","sources":["../../src/lib/schedule-audit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAgB,EAChB,SAAiB,EACjB,OAA4B,YAAY;IAExC,MAAM,OAAO,GAAG,KAAK,EAAE,KAAa,EAAmB,EAAE;QACvD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAC3B,YAAY,KAAK,uDAAuD,EACxE,EAAE,SAAS,EAAE,CACd,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5C,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,+EAA+E;IAC/E,oCAAoC;IACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAEtC,OAAO,CAAC,KAAK,CACX,4BAA4B,SAAS,aAAa,QAAQ,aAAa,QAAQ,cAAc,SAAS,EAAE,CACzG,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"schedule-audit.js","sourceRoot":"","sources":["../../src/lib/schedule-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gate-dispatch-wiring.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-dispatch-wiring.test.d.ts","sourceRoot":"","sources":["../../../src/scripts/__tests__/gate-dispatch-wiring.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ // @vitest-environment node
2
+ // Task 2378 — the dispatcher wiring.
3
+ //
4
+ // `dispatchDue` and the two dispatch queries live inside a module that calls
5
+ // `main()` at import time, so they cannot be imported by a test. The
6
+ // established answer here is to pin the source, the same way
7
+ // `sweep-excludes-suspended.test.ts` pins the WHERE clauses it models: the
8
+ // decision logic is unit-tested in `lib/__tests__/gate.test.ts`, and this file
9
+ // asserts the facts about the wiring that no unit test can reach.
10
+ //
11
+ // Each assertion below is a claim the task makes about ORDER or ABSENCE, and
12
+ // order and absence are exactly what a later edit breaks silently.
13
+ import { describe, it, expect } from "vitest";
14
+ import { readFileSync } from "node:fs";
15
+ import { dirname, resolve } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+ const HERE = dirname(fileURLToPath(import.meta.url));
18
+ const SOURCE = readFileSync(resolve(HERE, "../check-due-events.ts"), "utf-8");
19
+ const at = (needle) => {
20
+ const i = SOURCE.indexOf(needle);
21
+ expect(i, `not found in check-due-events.ts: ${needle}`).toBeGreaterThan(-1);
22
+ return i;
23
+ };
24
+ describe("the gate props reach the dispatcher", () => {
25
+ it("both dispatch queries return all three", () => {
26
+ // Two queries: one-time and recurring. A prop selected by one and not the
27
+ // other would gate one path and silently not the other.
28
+ for (const prop of ["e.gatePlugin AS gatePlugin", "e.gateTool AS gateTool", "e.gateArgs AS gateArgs"]) {
29
+ expect(SOURCE.split(prop).length - 1).toBe(2);
30
+ }
31
+ });
32
+ it("only the recurring loop resolves a gate", () => {
33
+ // A one-time row is already `eventStatus = 'due'` by the time dispatchDue
34
+ // runs, so it will never be selected again and a skip there is permanent.
35
+ // Dropping a routine for good is the opposite of what the gate is for.
36
+ expect(SOURCE.split("const gate = chooseGate({").length - 1).toBe(1);
37
+ });
38
+ it("the recurring call site passes the gate and the one-time call site passes null", () => {
39
+ expect(SOURCE.split("driver, fields, runId, gate)").length - 1).toBe(1);
40
+ expect(SOURCE.split("driver, fields, runId, null)").length - 1).toBe(1);
41
+ });
42
+ it("the one-time loop's null is explained, so a later edit does not read it as an oversight", () => {
43
+ const loop = SOURCE.slice(at("--- One-time events:"), at("--- Recurring events:"));
44
+ expect(loop).toContain("a one-time event is NEVER gated");
45
+ });
46
+ });
47
+ describe("ordering", () => {
48
+ it("the recurring loop advances nextRun BEFORE it calls dispatchDue", () => {
49
+ // The advance is the anti-double-fire guard, and the gate runs inside
50
+ // dispatchDue. Gating first would let a gated fire be re-selected on the
51
+ // next tick, replaying the check until it happened to pass.
52
+ //
53
+ // Sliced to the recurring loop rather than compared across the whole file:
54
+ // `dispatchDue` is DEFINED near the top and CALLED near the bottom, so a
55
+ // whole-file index comparison measures declaration order, not the order
56
+ // anything runs in.
57
+ const loop = SOURCE.slice(at("--- Recurring events:"), at("--- Suspended routines skipped"));
58
+ expect(loop.indexOf("SET e.lastTriggered = $now")).toBeGreaterThan(-1);
59
+ expect(loop.indexOf("SET e.lastTriggered = $now")).toBeLessThan(loop.indexOf("await dispatchDue("));
60
+ });
61
+ it("the one-time loop marks the row due before it calls dispatchDue", () => {
62
+ const loop = SOURCE.slice(at("--- One-time events:"), at("--- Recurring events:"));
63
+ expect(loop.indexOf("SET e.eventStatus = 'due'")).toBeGreaterThan(-1);
64
+ expect(loop.indexOf("SET e.eventStatus = 'due'")).toBeLessThan(loop.indexOf("await dispatchDue("));
65
+ });
66
+ it("the gate is evaluated BEFORE the inject", () => {
67
+ expect(at("await evaluateGate(")).toBeLessThan(at("await dispatchAgentTurn("));
68
+ });
69
+ it("the gate is inside the agent branch, not before the mode is known", () => {
70
+ // The action rail already runs headlessly with no model, so a gate there
71
+ // would save nothing and would need its own outcome vocabulary.
72
+ expect(at('if (mode.kind === "agent")')).toBeLessThan(at("await evaluateGate("));
73
+ expect(at("await evaluateGate(")).toBeLessThan(at('if (mode.kind === "action")'));
74
+ });
75
+ });
76
+ describe("the no-work branch", () => {
77
+ const branch = SOURCE.slice(at('if (verdict.kind === "no-work")'), at("const accountsDir"));
78
+ it("returns before reaching the inject", () => {
79
+ expect(branch).toContain("return false;");
80
+ expect(branch).not.toContain("dispatchAgentTurn");
81
+ });
82
+ it("writes lastDispatchResult = 'gated' and the timestamp", () => {
83
+ expect(branch).toContain("e.lastDispatchResult = 'gated'");
84
+ expect(branch).toContain("e.lastDispatchAt = $now");
85
+ });
86
+ it("closes the run record as gated, so the fires-without-records audit stays reconciled", () => {
87
+ expect(branch).toContain('outcome: "gated"');
88
+ });
89
+ it("emits op=skipped reason=no-work", () => {
90
+ expect(branch).toContain("op=skipped");
91
+ expect(branch).toContain("reason=no-work");
92
+ });
93
+ it("does not advance nextRun itself — the caller already did", () => {
94
+ expect(branch).not.toContain("e.nextRun");
95
+ });
96
+ it("swallows a Neo4j failure rather than aborting the sweep", () => {
97
+ expect(branch).toContain("} catch {");
98
+ });
99
+ });
100
+ describe("fail-open reaches the dispatch", () => {
101
+ it("only the no-work verdict returns early", () => {
102
+ // If a later edit widened this comparison — to `!== "has-work"`, say — every
103
+ // unreadable gate would silently mute its routine, which is the inversion
104
+ // this whole design guards against.
105
+ expect(SOURCE).toContain('if (verdict.kind === "no-work")');
106
+ expect(SOURCE).not.toContain('verdict.kind !== "has-work"');
107
+ });
108
+ });
109
+ describe("the ungated path is unchanged", () => {
110
+ it("the gate block is entered only when a gate is present", () => {
111
+ expect(at("if (gate) {")).toBeLessThan(at("await evaluateGate("));
112
+ });
113
+ });
114
+ describe("standing audits are called every tick", () => {
115
+ it("both gate audits are invoked from the audit block", () => {
116
+ expect(SOURCE).toContain("await auditGateAlwaysSkipping(driver, localAccountIds)");
117
+ expect(SOURCE).toContain("await auditGateWatermarkAge(driver, localAccountIds");
118
+ });
119
+ it("each is wrapped so a failure costs the tick nothing but an error line", () => {
120
+ expect(SOURCE).toContain("op=gate-census-error");
121
+ expect(SOURCE).toContain("op=gate-watermark-age-error");
122
+ });
123
+ it("they sit outside the dispatch loops, so they run on a tick with nothing due", () => {
124
+ expect(at("await auditFailingDispatch(")).toBeLessThan(at("await auditGateAlwaysSkipping("));
125
+ expect(at("await auditGateWatermarkAge(")).toBeLessThan(at("await reconcilePluginLifecycles("));
126
+ });
127
+ });
128
+ describe("the extracted transport", () => {
129
+ it("dispatchAction calls the shared callPluginTool rather than its own client", () => {
130
+ expect(SOURCE).toContain("await callPluginTool(actionPlugin, actionTool, actionArgs, eventAccountId)");
131
+ // The inline client is gone: two transports would be two places for the
132
+ // timeout, the ACCOUNT_ID scoping and the stderr capture to drift.
133
+ expect(SOURCE).not.toContain("new StdioClientTransport(");
134
+ expect(SOURCE).not.toContain('new Client({ name: "event-dispatcher"');
135
+ });
136
+ it("a timeout is still recorded as timeout, not as a generic error", () => {
137
+ expect(SOURCE).toContain("err instanceof PluginToolError");
138
+ expect(SOURCE).toContain('timedOut = err.kind === "timeout"');
139
+ expect(SOURCE).toContain('const outcome = timedOut ? "timeout" : "error"');
140
+ });
141
+ it("child stderr is still attached to the failure record", () => {
142
+ expect(SOURCE).toContain("childStderr = err.childStderr");
143
+ expect(SOURCE).toContain("Child stderr:");
144
+ });
145
+ });
146
+ //# sourceMappingURL=gate-dispatch-wiring.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-dispatch-wiring.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/gate-dispatch-wiring.test.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,33 @@ export declare function chooseDispatchMode(fields: {
36
36
  actionTool: string | null;
37
37
  actionArgs: string | null;
38
38
  }): DispatchMode;
39
+ /**
40
+ * Task 2378 — the precondition a gated routine must satisfy before the model is
41
+ * invoked. Three optional `:Event` props, handled exactly as `actionArgs` is: a
42
+ * JSON string passed to the tool verbatim, never interpreted here.
43
+ */
44
+ export interface EventGate {
45
+ plugin: string;
46
+ tool: string;
47
+ args: string | null;
48
+ }
49
+ /**
50
+ * Task 2378 — resolve the gate from its selected node fields.
51
+ *
52
+ * Plugin AND tool, mirroring the `action` branch of `chooseDispatchMode`: a row
53
+ * carrying one without the other names nothing callable, and treating it as a
54
+ * gate would fail open on every fire while reading as configured. `args` is
55
+ * optional for the same reason `actionArgs` is — a check taking no arguments is
56
+ * legitimate.
57
+ *
58
+ * A gate is evaluated only for an agent-mode dispatch. Write-time validation
59
+ * refuses one on an action-mode event, so nothing here has to re-decide that.
60
+ */
61
+ export declare function chooseGate(fields: {
62
+ gatePlugin: string | null;
63
+ gateTool: string | null;
64
+ gateArgs: string | null;
65
+ }): EventGate | null;
39
66
  /**
40
67
  * Task 2130 — which missing field made `chooseDispatchMode` resolve to
41
68
  * `{kind:'none'}`, for the `[check-due] op=dispatch-skipped` line.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-turn-dispatch.d.ts","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-turn-dispatch.d.ts","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,24 @@ export function chooseDispatchMode(fields) {
28
28
  }
29
29
  return { kind: "none" };
30
30
  }
31
+ /**
32
+ * Task 2378 — resolve the gate from its selected node fields.
33
+ *
34
+ * Plugin AND tool, mirroring the `action` branch of `chooseDispatchMode`: a row
35
+ * carrying one without the other names nothing callable, and treating it as a
36
+ * gate would fail open on every fire while reading as configured. `args` is
37
+ * optional for the same reason `actionArgs` is — a check taking no arguments is
38
+ * legitimate.
39
+ *
40
+ * A gate is evaluated only for an agent-mode dispatch. Write-time validation
41
+ * refuses one on an action-mode event, so nothing here has to re-decide that.
42
+ */
43
+ export function chooseGate(fields) {
44
+ if (fields.gatePlugin && fields.gateTool) {
45
+ return { plugin: fields.gatePlugin, tool: fields.gateTool, args: fields.gateArgs };
46
+ }
47
+ return null;
48
+ }
31
49
  /**
32
50
  * Task 2130 — which missing field made `chooseDispatchMode` resolve to
33
51
  * `{kind:'none'}`, for the `[check-due] op=dispatch-skipped` line.