@rubytech/create-maxy-code 0.1.486 → 0.1.487

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 (21) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/cloudflare/PLUGIN.md +3 -3
  3. package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +30 -8
  4. package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +22 -2
  5. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +23 -0
  6. package/payload/platform/plugins/cloudflare/mcp/__tests__/schema-exposed-dirs.test.ts +43 -0
  7. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +12 -2
  8. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.d.ts +2 -0
  9. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.d.ts.map +1 -0
  10. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.js +12 -0
  11. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.js.map +1 -0
  12. package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.d.ts +8 -0
  13. package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.d.ts.map +1 -0
  14. package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.js +12 -0
  15. package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.js.map +1 -0
  16. package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +12 -2
  17. package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -1
  18. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  19. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +17 -1
  20. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  21. package/payload/server/server.js +147 -102
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.486",
3
+ "version": "0.1.487",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -71,7 +71,7 @@ The setup-done claim only fires when `curl -I https://<hostname>` issued from ou
71
71
 
72
72
  ## Data-portal folder index
73
73
 
74
- The portal shows a sub-account's deliverable folders alongside what the client uploaded. Which folders those are is never a list in the code: it is derived per account from that account's own `SCHEMA.md` — the buckets in its `<!-- ontology-buckets -->` region plus `output`, intersected with its `allowed-top-level` block. A brand on a different vertical exposes different folders with no code change. `bin/schema-exposed-dirs.mjs` is the only place that decision is made.
74
+ The portal shows a sub-account's deliverable folders alongside what the client uploaded. Which folders those are is never a list in the code: it is derived per account from that account's own `SCHEMA.md` — the buckets in its `<!-- ontology-buckets -->` region plus `output`, intersected with its `allowed-top-level` block. A brand on a different vertical exposes different folders with no code change. `bin/schema-exposed-dirs.mjs` is the only place that decision is made. An operator can add non-ontology folders (a workflow folder such as `inbound-invoices`) by listing them in `exposeFolders` in the account's `data-portal.json`; each must match `[A-Za-z0-9_-]+` and is never a system folder (`agents`, `secrets`, `specialists`, `state`, `memory`, `cache`, `logs`, `tmp`) or dot-prefixed. Those extras union on top of the schema-derived set and, unlike ontology buckets, are not intersected with `allowed-top-level`; empty or absent behaves as before.
75
75
 
76
76
  `bin/portal-index-push.mjs` walks those folders and full-replaces the account's rows in the portal's D1 `directory` table each cycle. Metadata only — names, sizes, times — so listing survives the device being offline, and a deleted or renamed file converges on the next cycle without a tombstone. The scheduling heartbeat runs it hourly for every account carrying a `data-portal.json`; it is also runnable standalone, which is how it stays operable while the heartbeat spawn path is unproven on a device.
77
77
 
@@ -82,7 +82,7 @@ Exposure is narrowed twice. The install re-derives the account's exposed set fro
82
82
  What to watch, on the device:
83
83
 
84
84
  ```
85
- [portal-index] op=resolve account=<id> schemaPresent=<bool> allowed=<n> domainBuckets=<dirs|none> exposed=<dirs|none>
85
+ [portal-index] op=resolve account=<id> schemaPresent=<bool> allowed=<n> domainBuckets=<dirs|none> extraFolders=<n> exposed=<dirs|none>
86
86
  [portal-index] op=replace account=<id> deleted=all inserted=<n>
87
87
  [portal-index] op=verify account=<id> rowsAfter=<n> expected=<n>
88
88
  [portal-index] op=collision account=<id> dir=<dir> claimedBy=plugin-owned
@@ -90,7 +90,7 @@ What to watch, on the device:
90
90
  [portal-index] op=audit accounts=<n> stale=<n> never-ran=<n>
91
91
  ```
92
92
 
93
- `exposed=none` where deliverables exist means the schema was missing or carried no ontology region — not that the walk found nothing. `rowsAfter` disagreeing with `expected` is a half-applied replace. An `op=collision` line explains a folder that has silently vanished from the client's view, which nothing else would report. `op=exposed-changed` fires only on a delta, so it is rare and always worth reading; a `removed=` naming a populated bucket is the client-visible regression.
93
+ `exposed=none` where deliverables exist means the schema was missing or carried no ontology region — not that the walk found nothing. `rowsAfter` disagreeing with `expected` is a half-applied replace. An `op=collision` line explains a folder that has silently vanished from the client's view, which nothing else would report. `op=exposed-changed` fires only on a delta, so it is rare and always worth reading; a `removed=` naming a populated bucket is the client-visible regression. `extraFolders=<n>` counts the folders the operator requested in `exposeFolders`; a non-zero `extraFolders` with none of those names in `exposed=` means the guard dropped every one.
94
94
 
95
95
  `op=audit` is the standing check, and it is the only one that speaks when the push does **not**. It runs in-process inside the heartbeat rather than as a spawn, and reads only local state, so it cannot be blinded by the same failure it is watching for. It fires hourly even when everything is healthy — an audit that goes quiet on success is indistinguishable from an audit that stopped running. `result=never-ran` on an account with a `data-portal.json` means no cycle has ever succeeded for it; `result=stale` with `ageMin` means cycles have stopped. Its input is written only after `op=verify`, so a stale entry means the push stopped succeeding rather than merely stopped logging.
96
96
 
@@ -42,6 +42,20 @@ function readEnvFile(path) {
42
42
  return out
43
43
  }
44
44
 
45
+ /** Operator-named extra folders for an account, from its data-portal.json.
46
+ * Absent file, absent key, or a non-array value all yield []. The resolver
47
+ * applies the charset-and-system guard; this reader does not pre-filter, so the
48
+ * `extraFolders=<n>` count reflects what the operator asked for.
49
+ * @param {string} accountDir @returns {Promise<string[]>} */
50
+ export async function readExposeFolders(accountDir) {
51
+ try {
52
+ const cfg = JSON.parse(await readFile(join(accountDir, 'data-portal.json'), 'utf8'))
53
+ return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === 'string') : []
54
+ } catch {
55
+ return []
56
+ }
57
+ }
58
+
45
59
  /**
46
60
  * Files under `exposed` dirs, at any depth. Dot-prefixed entries are skipped at
47
61
  * every level: `.uploads-tmp/` holds in-flight upload partials (files.ts:25) and
@@ -85,7 +99,7 @@ export async function walkExposed(accountDir, exposed) {
85
99
  * @param {{ accountDir: string, accountId: string, dbName: string,
86
100
  * client: { query: (sql: string, params?: unknown[]) => Promise<Record<string, unknown>[]> },
87
101
  * log: (line: string) => void, nowIso: string,
88
- * previousExposed?: string[] }} opts
102
+ * exposeFolders?: string[], previousExposed?: string[] }} opts
89
103
  * @returns {Promise<{ exposed: string[], rows: number, schemaPresent: boolean }>}
90
104
  */
91
105
  export async function pushAccount(opts) {
@@ -98,10 +112,15 @@ export async function pushAccount(opts) {
98
112
  schemaText = null
99
113
  }
100
114
 
101
- const r = resolveExposedDirs(schemaText)
115
+ const exposeFolders = Array.isArray(opts.exposeFolders) ? opts.exposeFolders : []
116
+ const r = resolveExposedDirs(schemaText, exposeFolders)
117
+ // extraFolders is the REQUESTED count, not the accepted count: a non-zero
118
+ // extraFolders with none of those names in exposed= means the guard dropped
119
+ // every one, which is distinct from none configured (extraFolders=0).
102
120
  log(
103
121
  `${TAG} op=resolve account=${accountId} schemaPresent=${r.schemaPresent} allowed=${r.allowed.length} ` +
104
- `domainBuckets=${r.domainBuckets.join(',') || 'none'} exposed=${r.exposed.join(',') || 'none'}`,
122
+ `domainBuckets=${r.domainBuckets.join(',') || 'none'} extraFolders=${exposeFolders.length} ` +
123
+ `exposed=${r.exposed.join(',') || 'none'}`,
105
124
  )
106
125
  // The generator gives a plugin-claimed dir to the plugin-owned region only
107
126
  // (account-schema-owned-dirs.py:287), so this is normally silent. When it is
@@ -212,10 +231,10 @@ function arg(flag) {
212
231
  * Every account carrying a data-portal.json has a portal. The file's presence is
213
232
  * the enrolment signal — there is no separate flag to keep in sync with it.
214
233
  * @param {string} accountsRoot
215
- * @returns {Promise<{accountDir: string, accountId: string, dbName: string}[]>}
234
+ * @returns {Promise<{accountDir: string, accountId: string, dbName: string, exposeFolders: string[]}[]>}
216
235
  */
217
236
  async function portalAccounts(accountsRoot) {
218
- /** @type {{accountDir: string, accountId: string, dbName: string}[]} */ const out = []
237
+ /** @type {{accountDir: string, accountId: string, dbName: string, exposeFolders: string[]}[]} */ const out = []
219
238
  /** @type {string[]} */ let names
220
239
  try {
221
240
  names = await readdir(accountsRoot)
@@ -227,7 +246,10 @@ async function portalAccounts(accountsRoot) {
227
246
  try {
228
247
  const cfg = JSON.parse(await readFile(join(accountDir, 'data-portal.json'), 'utf8'))
229
248
  if (typeof cfg?.portalDbName === 'string' && cfg.portalDbName) {
230
- out.push({ accountDir, accountId, dbName: cfg.portalDbName })
249
+ const exposeFolders = Array.isArray(cfg?.exposeFolders)
250
+ ? cfg.exposeFolders.filter((f) => typeof f === 'string')
251
+ : []
252
+ out.push({ accountDir, accountId, dbName: cfg.portalDbName, exposeFolders })
231
253
  } else {
232
254
  console.error(`${TAG} op=skip account=${accountId} reason=no-portalDbName`)
233
255
  }
@@ -292,7 +314,7 @@ async function main() {
292
314
  process.exit(1)
293
315
  }
294
316
 
295
- /** @type {{accountDir: string, accountId: string, dbName: string}[]} */ let targets
317
+ /** @type {{accountDir: string, accountId: string, dbName: string, exposeFolders: string[]}[]} */ let targets
296
318
  if (process.argv.includes('--all-accounts')) {
297
319
  // Same derivation as the platform's own DATA_ROOT (data-path.ts:19), from
298
320
  // the PLATFORM_ROOT the heartbeat already passes.
@@ -307,7 +329,7 @@ async function main() {
307
329
  console.error(`${TAG} op=usage --account-dir <dir> --account <id> --db <name>`)
308
330
  process.exit(1)
309
331
  }
310
- targets = [{ accountDir, accountId, dbName }]
332
+ targets = [{ accountDir, accountId, dbName, exposeFolders: await readExposeFolders(accountDir) }]
311
333
  }
312
334
 
313
335
  const state = readState(platformRoot)
@@ -21,6 +21,18 @@ const OWNED_END = '<!-- plugin-owned-dirs:end -->'
21
21
  /** The delivery convention, always exposed when the account allows it. */
22
22
  export const ALWAYS_EXPOSED = 'output'
23
23
 
24
+ /** Folders that must never be named into exposure, even by an operator. The
25
+ * dot-prefixed `.git`/`.claude` are already excluded by the charset guard
26
+ * below. This is the not-system half of the extra-folder bound. */
27
+ const SYSTEM_DIRS = new Set(['agents', 'secrets', 'specialists', 'state', 'memory', 'cache', 'logs', 'tmp'])
28
+
29
+ /** An operator-named extra folder is accepted only as a single safe segment
30
+ * (the same charset the per-person `--folders` grant enforces) and never a
31
+ * system dir. This drops dot-prefixed names, slashes, and traversal such as
32
+ * `jobs/../secrets`, which would otherwise let the push walk index files under
33
+ * a system dir that the fetch route would refuse to serve. */
34
+ const SAFE_FOLDER = /^[A-Za-z0-9_-]+$/
35
+
24
36
  /**
25
37
  * The generator writes the ontology region with an ASCII hyphen and the
26
38
  * plugin-owned region with an em dash (account-schema-owned-dirs.py:294 vs
@@ -53,10 +65,11 @@ function allowedBlockOrNull(text) {
53
65
 
54
66
  /**
55
67
  * @param {string | null} schemaText Contents of accounts/<id>/SCHEMA.md, or null when absent.
68
+ * @param {string[]} [exposeFolders] Operator-named extra top-level folders. Empty or absent = today.
56
69
  * @returns {{ schemaPresent: boolean, allowed: string[], domainBuckets: string[],
57
70
  * pluginOwned: string[], collisions: string[], exposed: string[] }}
58
71
  */
59
- export function resolveExposedDirs(schemaText) {
72
+ export function resolveExposedDirs(schemaText, exposeFolders = []) {
60
73
  const empty = {
61
74
  schemaPresent: false,
62
75
  allowed: /** @type {string[]} */ ([]),
@@ -97,7 +110,14 @@ export function resolveExposedDirs(schemaText) {
97
110
  const collisions = domainBuckets.filter((d) => pluginOwned.includes(d))
98
111
 
99
112
  const candidates = [ALWAYS_EXPOSED, ...domainBuckets.filter((d) => !collisions.includes(d))]
100
- const exposed = [...new Set(candidates)].filter((d) => allowed.includes(d)).sort()
113
+ const ontologyExposed = [...new Set(candidates)].filter((d) => allowed.includes(d))
114
+ // Extras are unioned AFTER the ontology step and are deliberately NOT
115
+ // intersected with `allowed`: a workflow folder is legitimately outside the
116
+ // ontology set. The charset-plus-deny guard is the whole bound.
117
+ const extras = (Array.isArray(exposeFolders) ? exposeFolders : []).filter(
118
+ (f) => typeof f === 'string' && SAFE_FOLDER.test(f) && !SYSTEM_DIRS.has(f),
119
+ )
120
+ const exposed = [...new Set([...ontologyExposed, ...extras])].sort()
101
121
 
102
122
  return { schemaPresent: true, allowed, domainBuckets, pluginOwned, collisions, exposed }
103
123
  }
@@ -173,4 +173,27 @@ describe('pushAccount', () => {
173
173
  await push(fakeClient(), { log: (l: string) => lines.push(l) })
174
174
  expect(lines.some((l) => l.includes('schemaPresent=false') && l.includes('exposed=none'))).toBe(true)
175
175
  })
176
+
177
+ it('op=resolve carries extraFolders and the walk includes an operator folder', async () => {
178
+ // inbound-invoices is NOT in the fixture allowed block, so this also proves
179
+ // an extra bypasses the ontology/allowed intersection.
180
+ file('inbound-invoices/INV-42.pdf')
181
+ const lines: string[] = []
182
+ const c = fakeClient()
183
+ await push(c, { log: (l: string) => lines.push(l), exposeFolders: ['inbound-invoices'] })
184
+ expect(lines.some((l) => /op=resolve .*extraFolders=1/.test(l))).toBe(true)
185
+ expect(lines.some((l) => /exposed=.*inbound-invoices/.test(l))).toBe(true)
186
+ const inserted = c.calls.filter((x) => /INSERT INTO directory/i.test(x.sql)).map((x) => String(x.params[1]))
187
+ expect(inserted).toContain('inbound-invoices/INV-42.pdf')
188
+ })
189
+
190
+ it('with no exposeFolders the operator folder is not walked and extraFolders=0', async () => {
191
+ file('inbound-invoices/INV-42.pdf')
192
+ const lines: string[] = []
193
+ const c = fakeClient()
194
+ await push(c, { log: (l: string) => lines.push(l) })
195
+ const inserted = c.calls.filter((x) => /INSERT INTO directory/i.test(x.sql)).map((x) => String(x.params[1]))
196
+ expect(inserted).not.toContain('inbound-invoices/INV-42.pdf')
197
+ expect(lines.some((l) => /op=resolve .*extraFolders=0/.test(l))).toBe(true)
198
+ })
176
199
  })
@@ -85,4 +85,47 @@ describe('resolveExposedDirs', () => {
85
85
  const r = resolveExposedDirs('# no fence here')
86
86
  expect(r.exposed).toEqual([])
87
87
  })
88
+
89
+ it('unions an operator-named folder into exposed', () => {
90
+ const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['inbound-invoices'])
91
+ expect(r.exposed).toEqual(['inbound-invoices', 'output', 'quotes'])
92
+ })
93
+
94
+ it('exposes an extra folder that is absent from the allowed block', () => {
95
+ // inbound-invoices is deliberately NOT in ALLOWED — extras bypass that intersection.
96
+ const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['inbound-invoices'])
97
+ expect(r.exposed).toContain('inbound-invoices')
98
+ })
99
+
100
+ it('drops a system folder named as an extra', () => {
101
+ const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['secrets'])
102
+ expect(r.exposed).not.toContain('secrets')
103
+ expect(r.exposed).toEqual(['output', 'quotes'])
104
+ })
105
+
106
+ it('drops a traversal or dotted extra', () => {
107
+ const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['jobs/../secrets', '.git', '..'])
108
+ expect(r.exposed).toEqual(['output', 'quotes'])
109
+ })
110
+
111
+ it('an empty extras list equals today', () => {
112
+ const base = resolveExposedDirs(schema({ ontology: ONTOLOGY }))
113
+ expect(resolveExposedDirs(schema({ ontology: ONTOLOGY }), []).exposed).toEqual(base.exposed)
114
+ })
115
+
116
+ it('never applies extras when the schema is missing', () => {
117
+ const r = resolveExposedDirs(null, ['inbound-invoices'])
118
+ expect(r.exposed).toEqual([])
119
+ expect(r.schemaPresent).toBe(false)
120
+ })
121
+
122
+ it('never applies extras when the allowed block is absent', () => {
123
+ const r = resolveExposedDirs('# no fence here', ['inbound-invoices'])
124
+ expect(r.exposed).toEqual([])
125
+ })
126
+
127
+ it('dedupes an extra that is already an ontology bucket', () => {
128
+ const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['quotes'])
129
+ expect(r.exposed).toEqual(['output', 'quotes'])
130
+ })
88
131
  })
@@ -182,17 +182,27 @@ An account with no `SCHEMA.md` publishes nothing at all. That is deliberate and
182
182
  what the write-path guard does — the guard fails open so an unseeded account is not write-blocked,
183
183
  while a surface facing a client must fail closed.
184
184
 
185
+ An operator can publish extra folders that are not ontology buckets by listing them in
186
+ `exposeFolders` in the account's `data-portal.json`, for example a workflow folder like
187
+ `inbound-invoices`. Each name must be a single folder matching `[A-Za-z0-9_-]+` and is refused if it
188
+ is a system folder (`agents`, `secrets`, `specialists`, `state`, `memory`, `cache`, `logs`, `tmp`) or
189
+ dot-prefixed. These extras are added on top of the schema-derived set and, unlike ontology buckets,
190
+ are not intersected with the `allowed-top-level` block. An empty or absent list behaves exactly as
191
+ before.
192
+
185
193
  The heartbeat runs this hourly for every account carrying a `data-portal.json`. Run it once by hand
186
194
  after assembly so the client has something to see on their first sign-in, and check the output names
187
195
  the folders you expect:
188
196
 
189
197
  ```
190
- [portal-index] op=resolve account=<id> schemaPresent=true allowed=22 domainBuckets=quotes exposed=output,quotes
198
+ [portal-index] op=resolve account=<id> schemaPresent=true allowed=22 domainBuckets=quotes extraFolders=1 exposed=inbound-invoices,output,quotes
191
199
  [portal-index] op=verify account=<id> rowsAfter=41 expected=41
192
200
  ```
193
201
 
194
202
  `exposed=none` on an account that has deliverables means the schema was missing or its ontology
195
- region was absent — not that the walk found nothing.
203
+ region was absent — not that the walk found nothing. `extraFolders=<n>` counts the folders the
204
+ operator requested in `exposeFolders`; a non-zero `extraFolders` with none of those names in
205
+ `exposed=` means the guard dropped every one (a system or dot name, or a bad spelling).
196
206
 
197
207
  ## How a client browses, downloads and uploads
198
208
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=free-busy-url.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free-busy-url.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/free-busy-url.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildFreeBusyUrl } from '../free-busy-url.js';
3
+ describe('buildFreeBusyUrl', () => {
4
+ it('carries the account id and the escaped from/to', () => {
5
+ const url = buildFreeBusyUrl('19500', 'dddb9148-7ba4-4de7-a0da-6eadc5743eda', '2026-07-21T00:00:00Z', '2026-08-05T00:00:00Z');
6
+ expect(url).toContain('http://127.0.0.1:19500/api/calendar/free-busy');
7
+ expect(url).toContain('account=dddb9148-7ba4-4de7-a0da-6eadc5743eda');
8
+ expect(url).toContain('from=2026-07-21T00%3A00%3A00Z');
9
+ expect(url).toContain('to=2026-08-05T00%3A00%3A00Z');
10
+ });
11
+ });
12
+ //# sourceMappingURL=free-busy-url.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free-busy-url.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/free-busy-url.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAEtD,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,EAAE,sCAAsC,EAAE,sBAAsB,EAAE,sBAAsB,CAAC,CAAA;QAC7H,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,+CAA+C,CAAC,CAAA;QACtE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,8CAA8C,CAAC,CAAA;QACrE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAA;QACtD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Build the device-local free/busy URL the publish dispatcher fetches. The
3
+ * `account` param names which booking-site account's free/busy to compute, so a
4
+ * multi-tenant install refreshes every site rather than only the one the server
5
+ * resolves by default (Task 1890). Values are URL-encoded for the query string.
6
+ */
7
+ export declare function buildFreeBusyUrl(port: string, accountId: string, from: string, to: string): string;
8
+ //# sourceMappingURL=free-busy-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free-busy-url.d.ts","sourceRoot":"","sources":["../../src/lib/free-busy-url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMlG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Build the device-local free/busy URL the publish dispatcher fetches. The
3
+ * `account` param names which booking-site account's free/busy to compute, so a
4
+ * multi-tenant install refreshes every site rather than only the one the server
5
+ * resolves by default (Task 1890). Values are URL-encoded for the query string.
6
+ */
7
+ export function buildFreeBusyUrl(port, accountId, from, to) {
8
+ return (`http://127.0.0.1:${port}/api/calendar/free-busy` +
9
+ `?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}` +
10
+ `&account=${encodeURIComponent(accountId)}`);
11
+ }
12
+ //# sourceMappingURL=free-busy-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free-busy-url.js","sourceRoot":"","sources":["../../src/lib/free-busy-url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,SAAiB,EAAE,IAAY,EAAE,EAAU;IACxF,OAAO,CACL,oBAAoB,IAAI,yBAAyB;QACjD,SAAS,kBAAkB,CAAC,IAAI,CAAC,OAAO,kBAAkB,CAAC,EAAE,CAAC,EAAE;QAChE,YAAY,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAC5C,CAAA;AACH,CAAC"}
@@ -28,6 +28,7 @@ import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync, mkdtemp
28
28
  import { resolve, join, basename } from "node:path";
29
29
  import { homedir, tmpdir } from "node:os";
30
30
  import { resolveHouseScopedToken } from "../lib/house-scoped-token.js";
31
+ import { buildFreeBusyUrl } from "../lib/free-busy-url.js";
31
32
  function resolveConfigDir() {
32
33
  const platformRoot = process.env.PLATFORM_ROOT;
33
34
  if (!platformRoot)
@@ -41,7 +42,14 @@ function resolveConfigDir() {
41
42
  return brand.configDir;
42
43
  }
43
44
  const CONFIG_DIR = resolve(homedir(), resolveConfigDir());
44
- const LOCK_FILE = resolve(CONFIG_DIR, "publish-availability.lock");
45
+ // Per-account lock (Task 1890): the server spawns one dispatcher per booking-site
46
+ // account each tick, so a single shared lock would make all but one bail
47
+ // result=skipped reason=lock-held. Keyed on the account this run publishes,
48
+ // resolved the same way as `accountId` in main() (env, else the account dir's
49
+ // basename) so a run with only PUBLISH_ACCOUNT_DIR set still locks per account.
50
+ const LOCK_ACCOUNT = process.env.PUBLISH_ACCOUNT_ID ??
51
+ (process.env.PUBLISH_ACCOUNT_DIR ? basename(process.env.PUBLISH_ACCOUNT_DIR) : "default");
52
+ const LOCK_FILE = resolve(CONFIG_DIR, `publish-availability-${LOCK_ACCOUNT}.lock`);
45
53
  function acquireLock() {
46
54
  mkdirSync(CONFIG_DIR, { recursive: true });
47
55
  if (existsSync(LOCK_FILE)) {
@@ -182,7 +190,9 @@ async function main() {
182
190
  const from = utcMidnight(now, 0);
183
191
  const to = utcMidnight(now, daysAhead + 1);
184
192
  const nowIso = now.toISOString();
185
- const url = `http://127.0.0.1:${port}/api/calendar/free-busy?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
193
+ // Name the account so a multi-tenant install computes this site's free/busy,
194
+ // not whatever the endpoint resolves by default (Task 1890).
195
+ const url = buildFreeBusyUrl(port, accountId, from, to);
186
196
  let payload;
187
197
  try {
188
198
  // Bound the read so a wedged server cannot hold the PID lock.
@@ -1 +1 @@
1
- {"version":3,"file":"publish-availability.js","sourceRoot":"","sources":["../../src/scripts/publish-availability.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"publish-availability.js","sourceRoot":"","sources":["../../src/scripts/publish-availability.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"account-dir-schema-reconcile.d.ts","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"AA2EA,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;+DAE+D;AAC/D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAE9D;AAED;;8EAE8E;AAC9E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAcpE;AA0FD;;;gFAGgF;AAChF,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,MAAM,GAAG,eAAe,CAwDvF;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED;;;oCAGoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAwBtD;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;CACb;AAED;oDACoD;AACpD,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,aAAa,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3C,yBAAyB,CAiB3B"}
1
+ {"version":3,"file":"account-dir-schema-reconcile.d.ts","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"AA2FA,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;+DAE+D;AAC/D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAE9D;AAED;;8EAE8E;AAC9E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAcpE;AA0FD;;;gFAGgF;AAChF,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,MAAM,GAAG,eAAe,CAwDvF;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED;;;oCAGoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAwBtD;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;CACb;AAED;oDACoD;AACpD,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,aAAa,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3C,yBAAyB,CAiB3B"}
@@ -37,7 +37,17 @@ const QUARANTINE_DIR = '.quarantine';
37
37
  * an account carrying a stale/older-template/hand-edited schema whose allowed
38
38
  * block omits one of these must not have it moved. This is a fail-SAFE belt on
39
39
  * the control plane, the mirror of the guard's fail-OPEN on a missing schema —
40
- * operator strays are still quarantined; the account's own machinery is not. */
40
+ * operator strays are still quarantined; the account's own machinery is not.
41
+ *
42
+ * The second group is platform-written control-plane FILES the platform reads
43
+ * and writes at the account root every run. Unlike the tool-owned buckets, no
44
+ * plugin declares them into the SCHEMA.md allowed-top-level block, so without
45
+ * this belt the sweep quarantines them and the feature that reads each one goes
46
+ * dark: calendar-availability.json is the booking page's availability config (a
47
+ * quarantine froze a live booking page, Task 1877 fix); wa/webchat/telegram
48
+ * -channel-bindings.json route each channel's inbound; canonical-webchat-session
49
+ * .json pins the webchat session; session-titles.json holds operator renames.
50
+ * Each is `join(accountDir, <name>)` in platform code, none is operator data. */
41
51
  const PROTECTED_TOP_LEVEL = new Set([
42
52
  '.git',
43
53
  '.claude',
@@ -45,6 +55,12 @@ const PROTECTED_TOP_LEVEL = new Set([
45
55
  'SCHEMA.md',
46
56
  'account.json',
47
57
  'AGENTS.md',
58
+ 'calendar-availability.json',
59
+ 'wa-channel-bindings.json',
60
+ 'webchat-channel-bindings.json',
61
+ 'telegram-channel-bindings.json',
62
+ 'canonical-webchat-session.json',
63
+ 'session-titles.json',
48
64
  ]);
49
65
  /** Buckets whose depth fs-schema-guard.sh checks, with the same 3-segment cap.
50
66
  * Every other top-level bucket is tool-owned and unbounded — not walked. This
@@ -1 +1 @@
1
- {"version":3,"file":"account-dir-schema-reconcile.js","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-dir-schema-reconcile.js","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"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"}
@@ -1643,10 +1643,10 @@ var serveStatic = (options = { root: "" }) => {
1643
1643
  };
1644
1644
 
1645
1645
  // server/index.ts
1646
- import { readFileSync as readFileSync42, existsSync as existsSync38, watchFile, readdirSync as readdirSync26, statSync as statSync17 } from "fs";
1646
+ import { readFileSync as readFileSync43, existsSync as existsSync39, watchFile, readdirSync as readdirSync26, statSync as statSync17 } from "fs";
1647
1647
  import { spawn as spawn3 } from "child_process";
1648
1648
  import { createHash as createHash7 } from "crypto";
1649
- import { resolve as resolve38, join as join45, basename as basename12 } from "path";
1649
+ import { resolve as resolve39, join as join45, basename as basename12 } from "path";
1650
1650
  import { homedir as homedir4 } from "os";
1651
1651
  import { monitorEventLoopDelay } from "perf_hooks";
1652
1652
 
@@ -2920,7 +2920,7 @@ var credsSaveQueue = Promise.resolve();
2920
2920
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
2921
2921
  console.error(`${TAG6} draining credential save queue\u2026`);
2922
2922
  const timer = new Promise(
2923
- (resolve39) => setTimeout(() => resolve39("timeout"), timeoutMs)
2923
+ (resolve40) => setTimeout(() => resolve40("timeout"), timeoutMs)
2924
2924
  );
2925
2925
  const result = await Promise.race([
2926
2926
  credsSaveQueue.then(() => "drained"),
@@ -3097,11 +3097,11 @@ async function createWaSocket(opts) {
3097
3097
  return sock;
3098
3098
  }
3099
3099
  async function waitForConnection(sock) {
3100
- return new Promise((resolve39, reject) => {
3100
+ return new Promise((resolve40, reject) => {
3101
3101
  const handler = (update) => {
3102
3102
  if (update.connection === "open") {
3103
3103
  sock.ev.off("connection.update", handler);
3104
- resolve39();
3104
+ resolve40();
3105
3105
  }
3106
3106
  if (update.connection === "close") {
3107
3107
  sock.ev.off("connection.update", handler);
@@ -3209,7 +3209,7 @@ function isTimeoutError(err) {
3209
3209
  return Boolean(err?.__maxyTimeout);
3210
3210
  }
3211
3211
  function withTimeout(label, promise, timeoutMs) {
3212
- return new Promise((resolve39, reject) => {
3212
+ return new Promise((resolve40, reject) => {
3213
3213
  const timer = setTimeout(() => {
3214
3214
  const err = new Error(`${label} timed out after ${timeoutMs}ms`);
3215
3215
  err.__maxyTimeout = true;
@@ -3219,7 +3219,7 @@ function withTimeout(label, promise, timeoutMs) {
3219
3219
  promise.then(
3220
3220
  (value) => {
3221
3221
  clearTimeout(timer);
3222
- resolve39(value);
3222
+ resolve40(value);
3223
3223
  },
3224
3224
  (err) => {
3225
3225
  clearTimeout(timer);
@@ -4278,8 +4278,8 @@ async function persistWhatsAppMessage(input) {
4278
4278
  const { givenName, familyName } = splitName(input.pushName);
4279
4279
  const prev = sessionWriteLocks.get(input.cacheKey);
4280
4280
  let release;
4281
- const mine = new Promise((resolve39) => {
4282
- release = resolve39;
4281
+ const mine = new Promise((resolve40) => {
4282
+ release = resolve40;
4283
4283
  });
4284
4284
  const chained = (prev ?? Promise.resolve()).then(() => mine);
4285
4285
  sessionWriteLocks.set(input.cacheKey, chained);
@@ -6016,11 +6016,11 @@ async function connectWithReconnect(conn) {
6016
6016
  console.error(
6017
6017
  `${TAG17} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
6018
6018
  );
6019
- await new Promise((resolve39) => {
6020
- const timer = setTimeout(resolve39, delay);
6019
+ await new Promise((resolve40) => {
6020
+ const timer = setTimeout(resolve40, delay);
6021
6021
  conn.abortController.signal.addEventListener("abort", () => {
6022
6022
  clearTimeout(timer);
6023
- resolve39();
6023
+ resolve40();
6024
6024
  }, { once: true });
6025
6025
  });
6026
6026
  }
@@ -6028,16 +6028,16 @@ async function connectWithReconnect(conn) {
6028
6028
  }
6029
6029
  }
6030
6030
  function waitForDisconnectEvent(conn) {
6031
- return new Promise((resolve39) => {
6031
+ return new Promise((resolve40) => {
6032
6032
  if (!conn.sock) {
6033
- resolve39();
6033
+ resolve40();
6034
6034
  return;
6035
6035
  }
6036
6036
  const sock = conn.sock;
6037
6037
  const handler = (update) => {
6038
6038
  if (update.connection === "close") {
6039
6039
  sock.ev.off("connection.update", handler);
6040
- resolve39();
6040
+ resolve40();
6041
6041
  }
6042
6042
  };
6043
6043
  sock.ev.on("connection.update", handler);
@@ -6511,8 +6511,8 @@ async function handleInboundMessage(conn, msg) {
6511
6511
  const conversationKey = isGroup ? remoteJid : senderPhone;
6512
6512
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
6513
6513
  let resolvePending;
6514
- const sttPending = new Promise((resolve39) => {
6515
- resolvePending = resolve39;
6514
+ const sttPending = new Promise((resolve40) => {
6515
+ resolvePending = resolve40;
6516
6516
  });
6517
6517
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
6518
6518
  try {
@@ -6901,20 +6901,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
6901
6901
 
6902
6902
  // server/routes/health.ts
6903
6903
  function checkPort(port2, timeoutMs = 500) {
6904
- return new Promise((resolve39) => {
6904
+ return new Promise((resolve40) => {
6905
6905
  const socket = createConnection2(port2, "127.0.0.1");
6906
6906
  socket.setTimeout(timeoutMs);
6907
6907
  socket.once("connect", () => {
6908
6908
  socket.destroy();
6909
- resolve39(true);
6909
+ resolve40(true);
6910
6910
  });
6911
6911
  socket.once("error", () => {
6912
6912
  socket.destroy();
6913
- resolve39(false);
6913
+ resolve40(false);
6914
6914
  });
6915
6915
  socket.once("timeout", () => {
6916
6916
  socket.destroy();
6917
- resolve39(false);
6917
+ resolve40(false);
6918
6918
  });
6919
6919
  });
6920
6920
  }
@@ -8245,8 +8245,8 @@ async function startLogin(opts) {
8245
8245
  await clearAuth(authDir);
8246
8246
  let resolveCode = null;
8247
8247
  let rejectCode = null;
8248
- const codePromise = new Promise((resolve39, reject) => {
8249
- resolveCode = resolve39;
8248
+ const codePromise = new Promise((resolve40, reject) => {
8249
+ resolveCode = resolve40;
8250
8250
  rejectCode = reject;
8251
8251
  });
8252
8252
  const codeTimer = setTimeout(
@@ -14681,15 +14681,15 @@ function operatorRoleFor(config, userId) {
14681
14681
  async function buildAccountOptionList(accounts, userId) {
14682
14682
  const houseAccount = accounts.find((a) => a.config.role === "house");
14683
14683
  console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
14684
- const resolve39 = async (a) => {
14684
+ const resolve40 = async (a) => {
14685
14685
  const businessName = await fetchAccountName(a.accountId) || void 0;
14686
14686
  return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
14687
14687
  };
14688
14688
  const houseOptions = await Promise.all(
14689
- accounts.filter((a) => a.config.role === "house").map(resolve39)
14689
+ accounts.filter((a) => a.config.role === "house").map(resolve40)
14690
14690
  );
14691
14691
  const nonHouseOptions = await Promise.all(
14692
- accounts.filter((a) => a.config.role !== "house").map(resolve39)
14692
+ accounts.filter((a) => a.config.role !== "house").map(resolve40)
14693
14693
  );
14694
14694
  const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
14695
14695
  nonHouseOptions.sort((x, y) => {
@@ -24494,7 +24494,17 @@ app62.get("/free-busy", async (c) => {
24494
24494
  if (Number.isNaN(Date.parse(from)) || Number.isNaN(Date.parse(to))) {
24495
24495
  return c.json({ error: "from and to must be parseable ISO timestamps" }, 400);
24496
24496
  }
24497
- const account = resolveAccount();
24497
+ const accountParam = c.req.query("account");
24498
+ let account;
24499
+ if (accountParam) {
24500
+ account = listValidAccounts().find((a) => a.accountId === accountParam) ?? null;
24501
+ if (!account) {
24502
+ console.error(`[calendar] op=free-busy-unknown-account account="${accountParam}"`);
24503
+ return c.json({ error: "Availability not configured" }, 404);
24504
+ }
24505
+ } else {
24506
+ account = resolveAccount();
24507
+ }
24498
24508
  if (!account) return c.json({ error: "No account configured" }, 500);
24499
24509
  let config;
24500
24510
  try {
@@ -24546,6 +24556,8 @@ var ONT_END = "<!-- ontology-buckets:end -->";
24546
24556
  var OWNED_START = "<!-- plugin-owned-dirs:start -->";
24547
24557
  var OWNED_END = "<!-- plugin-owned-dirs:end -->";
24548
24558
  var ALWAYS_EXPOSED = "output";
24559
+ var SYSTEM_DIRS = /* @__PURE__ */ new Set(["agents", "secrets", "specialists", "state", "memory", "cache", "logs", "tmp"]);
24560
+ var SAFE_FOLDER = /^[A-Za-z0-9_-]+$/;
24549
24561
  var DOMAIN_LINE = /^- `([^`/]+)\/` - one folder per /;
24550
24562
  var OWNED_LINE = /^- `([^`/]+)\/` — /;
24551
24563
  function region(text, start, end) {
@@ -24565,7 +24577,7 @@ function allowedBlockOrNull(text) {
24565
24577
  }
24566
24578
  return null;
24567
24579
  }
24568
- function resolveExposedDirs(schemaText) {
24580
+ function resolveExposedDirs(schemaText, exposeFolders = []) {
24569
24581
  const empty = {
24570
24582
  schemaPresent: false,
24571
24583
  allowed: (
@@ -24607,7 +24619,11 @@ function resolveExposedDirs(schemaText) {
24607
24619
  const pluginOwned = dirsIn(owned, OWNED_LINE);
24608
24620
  const collisions = domainBuckets.filter((d) => pluginOwned.includes(d));
24609
24621
  const candidates = [ALWAYS_EXPOSED, ...domainBuckets.filter((d) => !collisions.includes(d))];
24610
- const exposed = [...new Set(candidates)].filter((d) => allowed.includes(d)).sort();
24622
+ const ontologyExposed = [...new Set(candidates)].filter((d) => allowed.includes(d));
24623
+ const extras = (Array.isArray(exposeFolders) ? exposeFolders : []).filter(
24624
+ (f) => typeof f === "string" && SAFE_FOLDER.test(f) && !SYSTEM_DIRS.has(f)
24625
+ );
24626
+ const exposed = [.../* @__PURE__ */ new Set([...ontologyExposed, ...extras])].sort();
24611
24627
  return { schemaPresent: true, allowed, domainBuckets, pluginOwned, collisions, exposed };
24612
24628
  }
24613
24629
 
@@ -24656,6 +24672,14 @@ async function readAccountSecret(accountId) {
24656
24672
  function isValidAccountId2(value) {
24657
24673
  return /^[A-Za-z0-9-]+$/.test(value);
24658
24674
  }
24675
+ async function readExposeFolders(accountDir) {
24676
+ try {
24677
+ const cfg = JSON.parse(await readFile6(join42(accountDir, "data-portal.json"), "utf8"));
24678
+ return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
24679
+ } catch {
24680
+ return [];
24681
+ }
24682
+ }
24659
24683
  async function resolveFetchTarget(accountDir, relPath) {
24660
24684
  let schemaText = null;
24661
24685
  try {
@@ -24663,7 +24687,8 @@ async function resolveFetchTarget(accountDir, relPath) {
24663
24687
  } catch {
24664
24688
  schemaText = null;
24665
24689
  }
24666
- const { exposed } = resolveExposedDirs(schemaText);
24690
+ const exposeFolders = await readExposeFolders(accountDir);
24691
+ const { exposed } = resolveExposedDirs(schemaText, exposeFolders);
24667
24692
  if (exposed.length === 0) return { ok: false, reason: "not-exposed" };
24668
24693
  const lexical = resolve32(accountDir, relPath);
24669
24694
  let root;
@@ -26484,16 +26509,16 @@ var WebchatGateway = class _WebchatGateway {
26484
26509
  * The public /api/chat route awaits this to return the reply on the same SSE
26485
26510
  * response, preserving the pre-756 POST→single-blob browser contract. */
26486
26511
  awaitReply(key, timeoutMs) {
26487
- return new Promise((resolve39) => {
26512
+ return new Promise((resolve40) => {
26488
26513
  const timer = setTimeout(() => {
26489
26514
  this.replyAwaiters.delete(key);
26490
- resolve39({ timeout: true });
26515
+ resolve40({ timeout: true });
26491
26516
  }, timeoutMs);
26492
26517
  if (timer.unref) timer.unref();
26493
26518
  this.replyAwaiters.set(key, (r) => {
26494
26519
  clearTimeout(timer);
26495
26520
  this.replyAwaiters.delete(key);
26496
- resolve39(r);
26521
+ resolve40(r);
26497
26522
  });
26498
26523
  });
26499
26524
  }
@@ -26504,11 +26529,11 @@ var WebchatGateway = class _WebchatGateway {
26504
26529
  * terminal dialog stays answerable). */
26505
26530
  awaitPermissionVerdict(p, timeoutMs) {
26506
26531
  const k = _WebchatGateway.promptKey(p.key, p.requestId);
26507
- return new Promise((resolve39) => {
26532
+ return new Promise((resolve40) => {
26508
26533
  this.pendingPrompts.get(k)?.resolve({ timeout: true });
26509
26534
  const timer = setTimeout(() => {
26510
26535
  this.pendingPrompts.delete(k);
26511
- resolve39({ timeout: true });
26536
+ resolve40({ timeout: true });
26512
26537
  }, timeoutMs);
26513
26538
  if (timer.unref) timer.unref();
26514
26539
  this.pendingPrompts.set(k, {
@@ -26517,7 +26542,7 @@ var WebchatGateway = class _WebchatGateway {
26517
26542
  resolve: (r) => {
26518
26543
  clearTimeout(timer);
26519
26544
  this.pendingPrompts.delete(k);
26520
- resolve39(r);
26545
+ resolve40(r);
26521
26546
  }
26522
26547
  });
26523
26548
  console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
@@ -28141,6 +28166,22 @@ function warnOnChannelAdminBindingDrift() {
28141
28166
  }
28142
28167
  }
28143
28168
 
28169
+ // server/lib/booking-site-accounts.ts
28170
+ import { existsSync as existsSync37, readFileSync as readFileSync41 } from "fs";
28171
+ import { resolve as resolve37 } from "path";
28172
+ function listBookingSiteAccounts(accounts) {
28173
+ return accounts.filter((a) => {
28174
+ const availPath = resolve37(a.accountDir, "calendar-availability.json");
28175
+ if (!existsSync37(availPath)) return false;
28176
+ try {
28177
+ const cfg = JSON.parse(readFileSync41(availPath, "utf-8"));
28178
+ return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
28179
+ } catch {
28180
+ return false;
28181
+ }
28182
+ });
28183
+ }
28184
+
28144
28185
  // app/lib/admin-sse-registry.ts
28145
28186
  var activeAdminSSEControllers = /* @__PURE__ */ new Set();
28146
28187
  function broadcastAdminShutdown(reason) {
@@ -28171,8 +28212,8 @@ function broadcastAdminShutdown(reason) {
28171
28212
 
28172
28213
  // ../lib/entitlement/src/index.ts
28173
28214
  import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
28174
- import { existsSync as existsSync37, readFileSync as readFileSync41, statSync as statSync16 } from "fs";
28175
- import { resolve as resolve37 } from "path";
28215
+ import { existsSync as existsSync38, readFileSync as readFileSync42, statSync as statSync16 } from "fs";
28216
+ import { resolve as resolve38 } from "path";
28176
28217
 
28177
28218
  // ../lib/entitlement/src/canonicalize.ts
28178
28219
  function canonicalize(value) {
@@ -28207,7 +28248,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
28207
28248
  var GRACE_DAYS = 7;
28208
28249
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
28209
28250
  function pubkeyPath(brand) {
28210
- return resolve37(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
28251
+ return resolve38(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
28211
28252
  }
28212
28253
  var memo = null;
28213
28254
  function memoKey(mtimeMs, account) {
@@ -28219,8 +28260,8 @@ function resolveEntitlement(brand, account) {
28219
28260
  if (brand.commercialMode !== true) {
28220
28261
  return logResolved(implicitTrust(account), null);
28221
28262
  }
28222
- const entitlementPath = resolve37(brand.configDir, "entitlement.json");
28223
- if (!existsSync37(entitlementPath)) {
28263
+ const entitlementPath = resolve38(brand.configDir, "entitlement.json");
28264
+ if (!existsSync38(entitlementPath)) {
28224
28265
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
28225
28266
  }
28226
28267
  const stat9 = statSync16(entitlementPath);
@@ -28235,7 +28276,7 @@ function resolveEntitlement(brand, account) {
28235
28276
  function verifyAndResolve(brand, entitlementPath, account) {
28236
28277
  let pubkeyPem;
28237
28278
  try {
28238
- pubkeyPem = readFileSync41(pubkeyPath(brand), "utf-8");
28279
+ pubkeyPem = readFileSync42(pubkeyPath(brand), "utf-8");
28239
28280
  } catch (err) {
28240
28281
  return logResolved(anonymousFallback("pubkey-missing"), {
28241
28282
  reason: "pubkey-missing"
@@ -28249,7 +28290,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
28249
28290
  }
28250
28291
  let envelope;
28251
28292
  try {
28252
- envelope = JSON.parse(readFileSync41(entitlementPath, "utf-8"));
28293
+ envelope = JSON.parse(readFileSync42(entitlementPath, "utf-8"));
28253
28294
  } catch {
28254
28295
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
28255
28296
  }
@@ -28413,12 +28454,12 @@ installMediaDownloadGuard();
28413
28454
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
28414
28455
  var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join45(PLATFORM_ROOT8, "config", "brand.json") : "";
28415
28456
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
28416
- if (BRAND_JSON_PATH && !existsSync38(BRAND_JSON_PATH)) {
28457
+ if (BRAND_JSON_PATH && !existsSync39(BRAND_JSON_PATH)) {
28417
28458
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
28418
28459
  }
28419
- if (BRAND_JSON_PATH && existsSync38(BRAND_JSON_PATH)) {
28460
+ if (BRAND_JSON_PATH && existsSync39(BRAND_JSON_PATH)) {
28420
28461
  try {
28421
- const parsed = JSON.parse(readFileSync42(BRAND_JSON_PATH, "utf-8"));
28462
+ const parsed = JSON.parse(readFileSync43(BRAND_JSON_PATH, "utf-8"));
28422
28463
  BRAND = { ...BRAND, ...parsed };
28423
28464
  } catch (err) {
28424
28465
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -28453,8 +28494,8 @@ var brandLoginOpts = {
28453
28494
  var ALIAS_DOMAINS_PATH = join45(homedir4(), BRAND.configDir, "alias-domains.json");
28454
28495
  function loadAliasDomains() {
28455
28496
  try {
28456
- if (!existsSync38(ALIAS_DOMAINS_PATH)) return null;
28457
- const parsed = JSON.parse(readFileSync42(ALIAS_DOMAINS_PATH, "utf-8"));
28497
+ if (!existsSync39(ALIAS_DOMAINS_PATH)) return null;
28498
+ const parsed = JSON.parse(readFileSync43(ALIAS_DOMAINS_PATH, "utf-8"));
28458
28499
  if (!Array.isArray(parsed)) {
28459
28500
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
28460
28501
  return null;
@@ -28527,7 +28568,7 @@ var waGateway = new WaGateway({
28527
28568
  fetchStandingRules: fetchAccountStandingRules,
28528
28569
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
28529
28570
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
28530
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve38(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
28571
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve39(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
28531
28572
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
28532
28573
  // path-validation scope) is the sender's effective SESSION account, resolved
28533
28574
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -28542,7 +28583,7 @@ var waGateway = new WaGateway({
28542
28583
  caption,
28543
28584
  accountId,
28544
28585
  maxyAccountId,
28545
- platformRoot: resolve38(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."))
28586
+ platformRoot: resolve39(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."))
28546
28587
  });
28547
28588
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
28548
28589
  },
@@ -29218,20 +29259,20 @@ app64.get("/agent-assets/:slug/:filename", (c) => {
29218
29259
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
29219
29260
  return c.text("Not found", 404);
29220
29261
  }
29221
- const filePath = resolve38(account.accountDir, "agents", slug, "assets", filename);
29222
- const expectedDir = resolve38(account.accountDir, "agents", slug, "assets");
29262
+ const filePath = resolve39(account.accountDir, "agents", slug, "assets", filename);
29263
+ const expectedDir = resolve39(account.accountDir, "agents", slug, "assets");
29223
29264
  if (!filePath.startsWith(expectedDir + "/")) {
29224
29265
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
29225
29266
  return c.text("Forbidden", 403);
29226
29267
  }
29227
- if (!existsSync38(filePath)) {
29268
+ if (!existsSync39(filePath)) {
29228
29269
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
29229
29270
  return c.text("Not found", 404);
29230
29271
  }
29231
29272
  const ext = "." + filename.split(".").pop()?.toLowerCase();
29232
29273
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
29233
29274
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
29234
- const body = readFileSync42(filePath);
29275
+ const body = readFileSync43(filePath);
29235
29276
  return c.body(body, 200, {
29236
29277
  "Content-Type": contentType,
29237
29278
  "Cache-Control": "public, max-age=3600"
@@ -29248,20 +29289,20 @@ app64.get("/generated/:filename", (c) => {
29248
29289
  console.error(`[generated] serve file=${filename} status=404`);
29249
29290
  return c.text("Not found", 404);
29250
29291
  }
29251
- const filePath = resolve38(account.accountDir, "generated", filename);
29252
- const expectedDir = resolve38(account.accountDir, "generated");
29292
+ const filePath = resolve39(account.accountDir, "generated", filename);
29293
+ const expectedDir = resolve39(account.accountDir, "generated");
29253
29294
  if (!filePath.startsWith(expectedDir + "/")) {
29254
29295
  console.error(`[generated] serve file=${filename} status=403`);
29255
29296
  return c.text("Forbidden", 403);
29256
29297
  }
29257
- if (!existsSync38(filePath)) {
29298
+ if (!existsSync39(filePath)) {
29258
29299
  console.error(`[generated] serve file=${filename} status=404`);
29259
29300
  return c.text("Not found", 404);
29260
29301
  }
29261
29302
  const ext = "." + filename.split(".").pop()?.toLowerCase();
29262
29303
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
29263
29304
  console.log(`[generated] serve file=${filename} status=200`);
29264
- const body = readFileSync42(filePath);
29305
+ const body = readFileSync43(filePath);
29265
29306
  return c.body(body, 200, {
29266
29307
  "Content-Type": contentType,
29267
29308
  "Cache-Control": "public, max-age=86400"
@@ -29274,9 +29315,9 @@ app64.route("/v", visitor_consent_default);
29274
29315
  var htmlCache = /* @__PURE__ */ new Map();
29275
29316
  var brandLogoPath = "/brand/maxy-monochrome.png";
29276
29317
  var brandIconPath = "/brand/maxy-monochrome.png";
29277
- if (BRAND_JSON_PATH && existsSync38(BRAND_JSON_PATH)) {
29318
+ if (BRAND_JSON_PATH && existsSync39(BRAND_JSON_PATH)) {
29278
29319
  try {
29279
- const fullBrand = JSON.parse(readFileSync42(BRAND_JSON_PATH, "utf-8"));
29320
+ const fullBrand = JSON.parse(readFileSync43(BRAND_JSON_PATH, "utf-8"));
29280
29321
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
29281
29322
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
29282
29323
  } catch {
@@ -29303,11 +29344,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
29303
29344
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
29304
29345
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
29305
29346
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
29306
- (p) => existsSync38(resolve38(process.cwd(), "public", p.replace(/^\//, "")))
29347
+ (p) => existsSync39(resolve39(process.cwd(), "public", p.replace(/^\//, "")))
29307
29348
  );
29308
29349
  var SW_SOURCE = (() => {
29309
29350
  try {
29310
- return readFileSync42(resolve38(process.cwd(), "public", "sw.js"), "utf-8");
29351
+ return readFileSync43(resolve39(process.cwd(), "public", "sw.js"), "utf-8");
29311
29352
  } catch {
29312
29353
  return null;
29313
29354
  }
@@ -29316,8 +29357,8 @@ function readInstalledVersion() {
29316
29357
  try {
29317
29358
  if (!PLATFORM_ROOT8) return "unknown";
29318
29359
  const versionFile = join45(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
29319
- if (!existsSync38(versionFile)) return "unknown";
29320
- const content = readFileSync42(versionFile, "utf-8").trim();
29360
+ if (!existsSync39(versionFile)) return "unknown";
29361
+ const content = readFileSync43(versionFile, "utf-8").trim();
29321
29362
  return content || "unknown";
29322
29363
  } catch {
29323
29364
  return "unknown";
@@ -29358,7 +29399,7 @@ var clientErrorReporterScript = `<script>
29358
29399
  function cachedHtml(file) {
29359
29400
  let html = htmlCache.get(file);
29360
29401
  if (!html) {
29361
- html = readFileSync42(resolve38(process.cwd(), "public", file), "utf-8");
29402
+ html = readFileSync43(resolve39(process.cwd(), "public", file), "utf-8");
29362
29403
  const productNameEsc = escapeHtml(BRAND.productName);
29363
29404
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
29364
29405
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -29380,8 +29421,8 @@ function loadBrandingCache(agentSlug) {
29380
29421
  const accountId = getDefaultAccountId();
29381
29422
  if (!accountId) return null;
29382
29423
  const cachePath = join45(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
29383
- if (!existsSync38(cachePath)) return null;
29384
- return JSON.parse(readFileSync42(cachePath, "utf-8"));
29424
+ if (!existsSync39(cachePath)) return null;
29425
+ return JSON.parse(readFileSync43(cachePath, "utf-8"));
29385
29426
  } catch {
29386
29427
  return null;
29387
29428
  }
@@ -29476,7 +29517,7 @@ app64.use("/vnc-popout.html", logViewerFetch);
29476
29517
  app64.get("/vnc-popout.html", (c) => {
29477
29518
  let html = htmlCache.get("vnc-popout.html");
29478
29519
  if (!html) {
29479
- html = readFileSync42(resolve38(process.cwd(), "public", "vnc-popout.html"), "utf-8");
29520
+ html = readFileSync43(resolve39(process.cwd(), "public", "vnc-popout.html"), "utf-8");
29480
29521
  const name = escapeHtml(BRAND.productName);
29481
29522
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
29482
29523
  html = html.replace("</head>", ` ${brandScript}
@@ -29614,10 +29655,10 @@ var httpServer = serve({ fetch: app64.fetch, port, hostname });
29614
29655
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29615
29656
  {
29616
29657
  const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
29617
- const reconcileScript = resolve38(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
29658
+ const reconcileScript = resolve39(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
29618
29659
  const RECONCILE_INTERVAL_MS = 12e4;
29619
29660
  const runReconcile = (ctx) => {
29620
- if (!existsSync38(reconcileScript)) return;
29661
+ if (!existsSync39(reconcileScript)) return;
29621
29662
  try {
29622
29663
  const child = spawn3(process.execPath, [reconcileScript], {
29623
29664
  env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
@@ -29640,10 +29681,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29640
29681
  }
29641
29682
  {
29642
29683
  const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
29643
- const outlookScript = resolve38(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
29684
+ const outlookScript = resolve39(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
29644
29685
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
29645
29686
  const runOutlookComplete = (ctx) => {
29646
- if (!existsSync38(outlookScript)) return;
29687
+ if (!existsSync39(outlookScript)) return;
29647
29688
  try {
29648
29689
  const child = spawn3(process.execPath, [outlookScript], {
29649
29690
  env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
@@ -29666,18 +29707,18 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29666
29707
  }
29667
29708
  {
29668
29709
  const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
29669
- const strandedAccountsDir = resolve38(auditRoot, "..", "data/accounts");
29710
+ const strandedAccountsDir = resolve39(auditRoot, "..", "data/accounts");
29670
29711
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
29671
29712
  const STRANDED_AGE_MS = 16 * 6e4;
29672
29713
  const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
29673
29714
  const runStrandedAudit = () => {
29674
29715
  try {
29675
- if (!existsSync38(strandedAccountsDir)) return;
29716
+ if (!existsSync39(strandedAccountsDir)) return;
29676
29717
  const now = Date.now();
29677
29718
  for (const name of readdirSync26(strandedAccountsDir)) {
29678
29719
  if (!STRANDED_UUID_RE.test(name)) continue;
29679
- const pendingPath2 = resolve38(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
29680
- if (!existsSync38(pendingPath2)) continue;
29720
+ const pendingPath2 = resolve39(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
29721
+ if (!existsSync39(pendingPath2)) continue;
29681
29722
  const ageMs = now - statSync17(pendingPath2).mtimeMs;
29682
29723
  if (ageMs > STRANDED_AGE_MS) {
29683
29724
  console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs / 1e3)}`);
@@ -29696,7 +29737,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29696
29737
  }
29697
29738
  {
29698
29739
  const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
29699
- const googleAccountsDir = resolve38(googleRoot, "..", "data/accounts");
29740
+ const googleAccountsDir = resolve39(googleRoot, "..", "data/accounts");
29700
29741
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
29701
29742
  const runGooglePendingAuditSafe = () => {
29702
29743
  try {
@@ -29711,10 +29752,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29711
29752
  firstRunDelayMs: 27e3,
29712
29753
  run: runGooglePendingAuditSafe
29713
29754
  });
29714
- const googleAuditScript = resolve38(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
29755
+ const googleAuditScript = resolve39(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
29715
29756
  const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
29716
29757
  const runGoogleAccountAudit = (ctx) => {
29717
- if (!existsSync38(googleAuditScript)) return;
29758
+ if (!existsSync39(googleAuditScript)) return;
29718
29759
  try {
29719
29760
  const child = spawn3(process.execPath, [googleAuditScript], {
29720
29761
  env: { ...process.env, PLATFORM_ROOT: googleRoot },
@@ -29774,18 +29815,18 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29774
29815
  }
29775
29816
  {
29776
29817
  const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
29777
- const publishScript = resolve38(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
29818
+ const publishScript = resolve39(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
29778
29819
  const PUBLISH_INTERVAL_MS = 3e5;
29779
- const currentAccount = () => {
29820
+ const bookingAccounts = () => {
29780
29821
  try {
29781
- return resolveAccount();
29822
+ return listBookingSiteAccounts(listValidAccounts());
29782
29823
  } catch (err) {
29783
- console.error(`[calendar-availability] op=publish result=error reason=account-resolve-failed err="${err.message}"`);
29784
- return null;
29824
+ console.error(`[calendar-availability] op=publish result=error reason=enumerate-failed err="${err.message}"`);
29825
+ return [];
29785
29826
  }
29786
29827
  };
29787
29828
  const spawnPublish = (account, ctx) => {
29788
- if (!existsSync38(publishScript)) return;
29829
+ if (!existsSync39(publishScript)) return;
29789
29830
  try {
29790
29831
  const child = spawn3(process.execPath, [publishScript], {
29791
29832
  env: {
@@ -29804,21 +29845,21 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29804
29845
  }
29805
29846
  };
29806
29847
  const auditSnapshotAge = (account) => {
29807
- const availPath = resolve38(account.accountDir, "calendar-availability.json");
29848
+ const availPath = resolve39(account.accountDir, "calendar-availability.json");
29808
29849
  let hasBookingSite = false;
29809
29850
  try {
29810
- if (existsSync38(availPath)) {
29811
- const cfg = JSON.parse(readFileSync42(availPath, "utf-8"));
29851
+ if (existsSync39(availPath)) {
29852
+ const cfg = JSON.parse(readFileSync43(availPath, "utf-8"));
29812
29853
  hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
29813
29854
  }
29814
29855
  } catch {
29815
29856
  }
29816
29857
  if (!hasBookingSite) return;
29817
- const statePath = resolve38(account.accountDir, "state", "booking-availability", "last-publish.json");
29858
+ const statePath = resolve39(account.accountDir, "state", "booking-availability", "last-publish.json");
29818
29859
  let lastSuccessAt = null;
29819
- if (existsSync38(statePath)) {
29860
+ if (existsSync39(statePath)) {
29820
29861
  try {
29821
- const rec = JSON.parse(readFileSync42(statePath, "utf-8"));
29862
+ const rec = JSON.parse(readFileSync43(statePath, "utf-8"));
29822
29863
  lastSuccessAt = rec.lastSuccessAt ?? null;
29823
29864
  } catch {
29824
29865
  console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
@@ -29830,10 +29871,14 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29830
29871
  console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=${ageMs ?? "na"}`);
29831
29872
  };
29832
29873
  const publishTick = (ctx) => {
29833
- const account = currentAccount();
29834
- if (!account) return;
29835
- spawnPublish(account, ctx);
29836
- auditSnapshotAge(account);
29874
+ for (const account of bookingAccounts()) {
29875
+ try {
29876
+ spawnPublish(account, ctx);
29877
+ auditSnapshotAge(account);
29878
+ } catch (err) {
29879
+ console.error(`[calendar-availability] op=publish accountId=${account.accountId} result=error reason=tick-failed err="${err.message}"`);
29880
+ }
29881
+ }
29837
29882
  };
29838
29883
  registerLoop({
29839
29884
  name: "calendar-availability-publish",
@@ -29847,11 +29892,11 @@ startTimeEntryCensus(() => getSession());
29847
29892
  startLedgerCensus(() => getSession());
29848
29893
  {
29849
29894
  const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
29850
- const auditScript = resolve38(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
29895
+ const auditScript = resolve39(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
29851
29896
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
29852
29897
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
29853
29898
  const runConnectorAudit = (ctx) => {
29854
- if (!existsSync38(auditScript)) return;
29899
+ if (!existsSync39(auditScript)) return;
29855
29900
  try {
29856
29901
  const child = spawn3(process.execPath, [auditScript], {
29857
29902
  env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
@@ -29971,11 +30016,11 @@ try {
29971
30016
  var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
29972
30017
  async function runAdminUserReconcileTick() {
29973
30018
  try {
29974
- if (!existsSync38(USERS_FILE)) {
30019
+ if (!existsSync39(USERS_FILE)) {
29975
30020
  console.error("[adminuser-self-heal] skip reason=no-users-file");
29976
30021
  return;
29977
30022
  }
29978
- const usersRaw = readFileSync42(USERS_FILE, "utf-8").trim();
30023
+ const usersRaw = readFileSync43(USERS_FILE, "utf-8").trim();
29979
30024
  if (!usersRaw) {
29980
30025
  console.error("[adminuser-self-heal] skip reason=empty-users-file");
29981
30026
  return;
@@ -30022,8 +30067,8 @@ registerLoop({
30022
30067
  });
30023
30068
  var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
30024
30069
  function countUsersRows() {
30025
- if (!existsSync38(USERS_FILE)) return 0;
30026
- const raw = readFileSync42(USERS_FILE, "utf-8").trim();
30070
+ if (!existsSync39(USERS_FILE)) return 0;
30071
+ const raw = readFileSync43(USERS_FILE, "utf-8").trim();
30027
30072
  if (!raw) return 0;
30028
30073
  const users = JSON.parse(raw);
30029
30074
  return users.filter((u) => typeof u.userId === "string").length;
@@ -30156,7 +30201,7 @@ if (bootAccountConfig?.whatsapp) {
30156
30201
  }
30157
30202
  init({
30158
30203
  configDir: configDirForWhatsApp,
30159
- platformRoot: resolve38(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..")),
30204
+ platformRoot: resolve39(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..")),
30160
30205
  accountConfig: bootAccountConfig,
30161
30206
  onMessage: async (msg) => {
30162
30207
  if (isObserveAccount(msg.accountId)) {