@rubytech/create-maxy-code 0.1.416 → 0.1.417
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/outlook-client-id-env.test.js +46 -0
- package/dist/index.js +31 -0
- package/dist/port-resolution.js +8 -1
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -0
- package/payload/platform/lib/account-enumeration/dist/__tests__/is-provisioned.test.d.ts +2 -0
- package/payload/platform/lib/account-enumeration/dist/__tests__/is-provisioned.test.d.ts.map +1 -0
- package/payload/platform/lib/account-enumeration/dist/__tests__/is-provisioned.test.js +81 -0
- package/payload/platform/lib/account-enumeration/dist/__tests__/is-provisioned.test.js.map +1 -0
- package/payload/platform/lib/account-enumeration/dist/index.d.ts +17 -0
- package/payload/platform/lib/account-enumeration/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/account-enumeration/dist/index.js +46 -9
- package/payload/platform/lib/account-enumeration/dist/index.js.map +1 -1
- package/payload/platform/lib/account-enumeration/src/__tests__/is-provisioned.test.ts +86 -0
- package/payload/platform/lib/account-enumeration/src/index.ts +45 -9
- package/payload/platform/lib/account-scope/dist/index.d.ts +14 -5
- package/payload/platform/lib/account-scope/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/account-scope/dist/index.js +14 -5
- package/payload/platform/lib/account-scope/dist/index.js.map +1 -1
- package/payload/platform/lib/account-scope/src/index.ts +22 -5
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +43 -10
- package/payload/platform/plugins/docs/references/outlook-guide.md +42 -9
- package/payload/platform/plugins/email/references/email-reference.md +1 -1
- package/payload/platform/plugins/filesystem/PLUGIN.md +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.js +16 -2
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js +8 -3
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.js +2 -2
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.js.map +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index-testable.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index-testable.js +14 -5
- package/payload/platform/plugins/memory/mcp/dist/index-testable.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +5 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j-constraint.d.ts +29 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j-constraint.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j-constraint.js +44 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j-constraint.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/owner-person-embed-text.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/owner-person-embed-text.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/owner-person-embed-text.test.js +22 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/owner-person-embed-text.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-bootstrap.test.js +105 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-bootstrap.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-embed.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-embed.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-embed.test.js +78 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-embed.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-tool-account.test.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-tool-account.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +0 -5
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +2 -12
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +106 -10
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +40 -7
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js +137 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/calendar-write.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/calendar-write.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/calendar-write.test.js +186 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/calendar-write.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +110 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-retry.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-retry.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-retry.test.js +108 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-retry.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js +13 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/message.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/message.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/message.test.js +32 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/message.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-store.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-store.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-store.test.js +67 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-store.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js +7 -5
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/write-tools.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/write-tools.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/write-tools.test.js +141 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/write-tools.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +69 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +129 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-store.d.ts +39 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-store.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-store.js +101 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pending-store.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js +3 -2
- package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +187 -5
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +34 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +96 -7
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts +31 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js +30 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +41 -17
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +87 -28
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-cancel.d.ts +17 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-cancel.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-cancel.js +38 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-cancel.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-create.d.ts +29 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-create.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-create.js +50 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-create.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-freebusy.d.ts +34 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-freebusy.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-freebusy.js +46 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-freebusy.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-respond.d.ts +15 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-respond.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-respond.js +27 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-respond.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-update.d.ts +11 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-update.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-update.js +20 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-update.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.d.ts +17 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.js +26 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts +11 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +26 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts +14 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js +26 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/scripts/verify-doc-impl.sh +2 -2
- package/payload/platform/plugins/outlook/references/auth.md +51 -54
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +97 -4
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +34 -9
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +9 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +18 -0
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +16 -0
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +7 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -2
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-CBlE6FB4.js → AdminLoginScreens-CBTx7ZPK.js} +1 -1
- package/payload/server/public/assets/{AdminShell-d1WQ3lLu.js → AdminShell-DPHUeXea.js} +1 -1
- package/payload/server/public/assets/{Checkbox-B0pbYJDQ.js → Checkbox-BHTxekRB.js} +1 -1
- package/payload/server/public/assets/{Transcript-CYaAPBFX.js → Transcript-5kLbBInN.js} +1 -1
- package/payload/server/public/assets/{admin-CVh9HO-f.js → admin-BWCLE32N.js} +1 -1
- package/payload/server/public/assets/{browser-C4f_D4Ih.js → browser-CRvCPsvV.js} +1 -1
- package/payload/server/public/assets/{calendar-WUxQ4fVo.js → calendar-BI-kd-QP.js} +1 -1
- package/payload/server/public/assets/chat-DFy8hb1y.js +1 -0
- package/payload/server/public/assets/chevron-left-Bggm5B5U.js +1 -0
- package/payload/server/public/assets/data-HvZ69Ya1.js +1 -0
- package/payload/server/public/assets/{graph-BNXE6mKP.js → graph-BFSyW_5i.js} +1 -1
- package/payload/server/public/assets/{graph-labels-Csnovm_c.js → graph-labels-DEjD_qJh.js} +1 -1
- package/payload/server/public/assets/{maximize-2-WRUJsg5n.js → maximize-2-BcMJNeCB.js} +1 -1
- package/payload/server/public/assets/{operator-CXtygMh6.js → operator-Dtvm9ero.js} +1 -1
- package/payload/server/public/assets/{page-DjpQp_ir.js → page-C_pm3hl3.js} +1 -1
- package/payload/server/public/assets/{page-IQDLdebG.js → page-TXi9dmaB.js} +1 -1
- package/payload/server/public/assets/{public-DSeYu61E.js → public-DBx3U0r8.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BayMWwfc.js → rotate-ccw-8ti3QkeY.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-BUvlETHN.css +1 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-C9aLg8yI.js → useSubAccountSwitcher-Bc5dOBdI.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +5 -5
- package/payload/server/public/chat.html +9 -9
- package/payload/server/public/data.html +8 -8
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +11 -11
- package/payload/server/public/operator.html +11 -11
- package/payload/server/public/public.html +9 -9
- package/payload/server/server.js +8 -2
- package/payload/server/public/assets/chat-NJ2HXhOf.js +0 -1
- package/payload/server/public/assets/chevron-left-Da-iZGi_.js +0 -1
- package/payload/server/public/assets/data-ZUdT44Ba.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-CRZfyJXR.css +0 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// acceptance gate for OUTLOOK_CLIENT_ID stamping in the claude-session-manager
|
|
2
|
+
// systemd unit (Task 1473).
|
|
3
|
+
//
|
|
4
|
+
// The outlook MCP reads process.env.OUTLOOK_CLIENT_ID; the session manager is
|
|
5
|
+
// the process that spawns claude -> MCP, so the client ID must land on this
|
|
6
|
+
// unit's Environment= block. Two invariants:
|
|
7
|
+
// (a) a non-empty brand outlookClientId emits BOTH
|
|
8
|
+
// `Environment=OUTLOOK_CLIENT_ID=<id>` and
|
|
9
|
+
// `Environment=OUTLOOK_TENANT_ID=common` (multi-tenant /common app).
|
|
10
|
+
// (b) an empty / absent brand value emits NEITHER line — the plugin stays
|
|
11
|
+
// inert on that brand exactly as before (no regression), and the MCP's
|
|
12
|
+
// module-init no-throw path keeps the registry intact.
|
|
13
|
+
import test from "node:test";
|
|
14
|
+
import assert from "node:assert/strict";
|
|
15
|
+
import { buildClaudeSessionManagerUnitFile } from "../port-resolution.js";
|
|
16
|
+
const ACCOUNT_ID = "12345678-9abc-def0-1234-56789abcdef0";
|
|
17
|
+
const CLIENT_ID = "0fa68fe2-8bec-4007-a0c7-776636fbcf97";
|
|
18
|
+
function build(outlookClientId) {
|
|
19
|
+
return buildClaudeSessionManagerUnitFile({
|
|
20
|
+
productName: "SiteDesk",
|
|
21
|
+
brandHostname: "sitedesk-code",
|
|
22
|
+
installDir: "/home/me/sitedesk-code",
|
|
23
|
+
persistDir: "/home/me/.sitedesk-code",
|
|
24
|
+
claudeSessionManagerPort: 19402,
|
|
25
|
+
brandPort: 19300,
|
|
26
|
+
maxyUiInternalPort: 19301,
|
|
27
|
+
accountId: ACCOUNT_ID,
|
|
28
|
+
cdpPort: 9224,
|
|
29
|
+
outlookClientId,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
test("stamps OUTLOOK_CLIENT_ID + OUTLOOK_TENANT_ID for a non-empty brand value", () => {
|
|
33
|
+
const unit = build(CLIENT_ID);
|
|
34
|
+
assert.match(unit, new RegExp(`^Environment=OUTLOOK_CLIENT_ID=${CLIENT_ID}$`, "m"), "OUTLOOK_CLIENT_ID line missing or malformed");
|
|
35
|
+
assert.match(unit, /^Environment=OUTLOOK_TENANT_ID=common$/m, "OUTLOOK_TENANT_ID=common line missing");
|
|
36
|
+
});
|
|
37
|
+
test("stamps NEITHER line when the brand value is empty", () => {
|
|
38
|
+
const unit = build("");
|
|
39
|
+
assert.doesNotMatch(unit, /OUTLOOK_CLIENT_ID/, "unexpected OUTLOOK_CLIENT_ID on empty brand");
|
|
40
|
+
assert.doesNotMatch(unit, /OUTLOOK_TENANT_ID/, "unexpected OUTLOOK_TENANT_ID on empty brand");
|
|
41
|
+
});
|
|
42
|
+
test("stamps NEITHER line when the brand value is absent", () => {
|
|
43
|
+
const unit = build(undefined);
|
|
44
|
+
assert.doesNotMatch(unit, /OUTLOOK_CLIENT_ID/, "unexpected OUTLOOK_CLIENT_ID on absent brand");
|
|
45
|
+
assert.doesNotMatch(unit, /OUTLOOK_TENANT_ID/, "unexpected OUTLOOK_TENANT_ID on absent brand");
|
|
46
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -3579,6 +3579,32 @@ function installServiceDarwin() {
|
|
|
3579
3579
|
else
|
|
3580
3580
|
envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `NODE_BIN=${nodeBin}\n`;
|
|
3581
3581
|
}
|
|
3582
|
+
// Task 1473 — darwin has no systemd EnvironmentFile primitive, so the vendor
|
|
3583
|
+
// Outlook app env is mirrored into .env (the wrapper sources it before exec).
|
|
3584
|
+
// Symmetric with the Linux unit, which is rebuilt wholesale each run: a
|
|
3585
|
+
// non-empty brand outlookClientId upserts BOTH vars together; empty / absent
|
|
3586
|
+
// STRIPS both lines. Stripping matters because .env persists across installs —
|
|
3587
|
+
// without it, a brand whose outlookClientId is later blanked (vendor-app
|
|
3588
|
+
// rotation/revocation) would keep sourcing a stale, now-invalid client ID and
|
|
3589
|
+
// keep reporting clientIdConfigured=true against its current empty intent.
|
|
3590
|
+
if (BRAND.outlookClientId) {
|
|
3591
|
+
for (const [key, value] of [
|
|
3592
|
+
["OUTLOOK_CLIENT_ID", BRAND.outlookClientId],
|
|
3593
|
+
["OUTLOOK_TENANT_ID", "common"],
|
|
3594
|
+
]) {
|
|
3595
|
+
const re = new RegExp(`^${key}=.*$`, "m");
|
|
3596
|
+
if (re.test(envContent))
|
|
3597
|
+
envContent = envContent.replace(re, `${key}=${value}`);
|
|
3598
|
+
else
|
|
3599
|
+
envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `${key}=${value}\n`;
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
else {
|
|
3603
|
+
for (const key of ["OUTLOOK_CLIENT_ID", "OUTLOOK_TENANT_ID"]) {
|
|
3604
|
+
envContent = envContent.replace(new RegExp(`^${key}=.*\\n?`, "m"), "");
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
logFile(` [installer] op=outlook-client-id brand=${BRAND.hostname} stamped=${BRAND.outlookClientId ? "true" : "false"}`);
|
|
3582
3608
|
writeFileSync(envPath, envContent);
|
|
3583
3609
|
logFile(` .env: DISPLAY_MODE=${DISPLAY_MODE}, EMBED_MODEL=${EMBED_MODEL}, EMBED_DIMENSIONS=${EMBED_DIMS}, NEO4J_URI=bolt://localhost:${NEO4J_PORT}, PORT=${PORT}, MAXY_UI_INTERNAL_PORT=${PORT} (darwin-collapsed), CLAUDE_SESSION_MANAGER_PORT=${BRAND.claudeSessionManagerPort}, HOSTNAME=0.0.0.0, ACCOUNT_ID=${installAccountId.slice(0, 8)}…, CLAUDE_CONFIG_DIR=${persistDir}/.claude, CLAUDE_BIN=${canonicalClaude ?? "unresolved(PATH)"}, NODE_BIN=${nodeBin}, PATH=${darwinServiceEnvPath}`);
|
|
3584
3610
|
}
|
|
@@ -4161,9 +4187,14 @@ function installService() {
|
|
|
4161
4187
|
maxyUiInternalPort: MAXY_UI_INTERNAL_PORT,
|
|
4162
4188
|
accountId: installAccountId,
|
|
4163
4189
|
cdpPort: CDP_PORT_BRAND,
|
|
4190
|
+
outlookClientId: BRAND.outlookClientId,
|
|
4164
4191
|
});
|
|
4165
4192
|
writeFileSync(join(serviceDir, claudeSessionManagerUnitName), claudeSessionManagerUnit);
|
|
4166
4193
|
logFile(` ${claudeSessionManagerUnitName}: CLAUDE_SESSION_MANAGER_PORT=${CLAUDE_SESSION_MANAGER_PORT_BRAND} MAXY_UI_INTERNAL_PORT=${MAXY_UI_INTERNAL_PORT}`);
|
|
4194
|
+
// Task 1473 — standing install-time signal reconciling brand.json intent
|
|
4195
|
+
// (a non-empty outlookClientId) against what the unit shipped. `stamped=false`
|
|
4196
|
+
// while the brand has a value is the mis-stamp signature.
|
|
4197
|
+
logFile(` [installer] op=outlook-client-id brand=${BRAND.hostname} stamped=${BRAND.outlookClientId ? "true" : "false"}`);
|
|
4167
4198
|
// Task 250 — write the brand-agnostic `claude-ptys.slice` unit. Every
|
|
4168
4199
|
// brand's session manager drops its per-spawn scope units under this
|
|
4169
4200
|
// slice. Writing it once per install is idempotent (the content is
|
package/dist/port-resolution.js
CHANGED
|
@@ -128,6 +128,13 @@ export function buildClaudeSessionManagerUnitFile(o) {
|
|
|
128
128
|
if (!o.accountId) {
|
|
129
129
|
throw new Error("buildClaudeSessionManagerUnitFile: accountId is required — caller must resolve the on-disk account UUID before stamping the systemd unit.");
|
|
130
130
|
}
|
|
131
|
+
// Task 1473 — a non-empty brand outlookClientId adds the vendor Outlook app
|
|
132
|
+
// env. Both lines land together so OUTLOOK_TENANT_ID (multi-tenant /common)
|
|
133
|
+
// never trails a bare client ID. Empty / absent brands stamp neither line —
|
|
134
|
+
// the plugin stays inert, no regression.
|
|
135
|
+
const outlookEnv = o.outlookClientId
|
|
136
|
+
? `\nEnvironment=OUTLOOK_CLIENT_ID=${o.outlookClientId}\nEnvironment=OUTLOOK_TENANT_ID=common`
|
|
137
|
+
: "";
|
|
131
138
|
return `[Unit]
|
|
132
139
|
Description=${o.productName} Claude Session Manager
|
|
133
140
|
After=network.target
|
|
@@ -149,7 +156,7 @@ Environment=PLATFORM_ROOT=${o.installDir}/platform
|
|
|
149
156
|
Environment=MAXY_BRAND_PORT=${o.brandPort}
|
|
150
157
|
Environment=MAXY_UI_INTERNAL_PORT=${o.maxyUiInternalPort}
|
|
151
158
|
Environment=PLATFORM_PORT=${o.maxyUiInternalPort}
|
|
152
|
-
Environment=CDP_PORT=${o.cdpPort}
|
|
159
|
+
Environment=CDP_PORT=${o.cdpPort}${outlookEnv}
|
|
153
160
|
EnvironmentFile=-${o.persistDir}/.env
|
|
154
161
|
StandardOutput=append:${o.persistDir}/logs/server.log
|
|
155
162
|
StandardError=append:${o.persistDir}/logs/server.log
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"websockifyPort": 6080,
|
|
15
15
|
"cdpPort": 9222,
|
|
16
16
|
"claudeSessionManagerPort": 19400,
|
|
17
|
+
"outlookClientId": "",
|
|
17
18
|
"commercialMode": false,
|
|
18
19
|
"vertical": "schema-knowledge-work",
|
|
19
20
|
"shipsPremiumBundles": ["venture-studio", "writer-craft", "teaching", "management-consulting"],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-provisioned.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/is-provisioned.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_os_1 = require("node:os");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const index_js_1 = require("../index.js");
|
|
12
|
+
const BOOT_ID = "12345678-9abc-def0-1234-56789abcdef0";
|
|
13
|
+
const LATER_ID = "99999999-aaaa-bbbb-cccc-dddddddddddd";
|
|
14
|
+
/** One valid account dir (BOOT_ID) that existed at "boot". */
|
|
15
|
+
function makeFixture() {
|
|
16
|
+
const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "acct-prov-"));
|
|
17
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, BOOT_ID));
|
|
18
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, BOOT_ID, "account.json"), JSON.stringify({ id: BOOT_ID }));
|
|
19
|
+
return root;
|
|
20
|
+
}
|
|
21
|
+
/** Provision a second account dir on disk AFTER boot (simulates account_create). */
|
|
22
|
+
function provisionLater(root) {
|
|
23
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, LATER_ID));
|
|
24
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, LATER_ID, "account.json"), JSON.stringify({ id: LATER_ID }));
|
|
25
|
+
}
|
|
26
|
+
(0, node_test_1.default)("isProvisionedAccount: a created-after-boot id resolves via re-scan on miss", () => {
|
|
27
|
+
(0, index_js_1._resetEnumerationCache)();
|
|
28
|
+
const root = makeFixture();
|
|
29
|
+
try {
|
|
30
|
+
// Warm the cache at "boot" — only BOOT_ID is present.
|
|
31
|
+
strict_1.default.deepEqual((0, index_js_1.enumerateValidAccountIds)(root), [BOOT_ID]);
|
|
32
|
+
// A sub-account is provisioned after the snapshot.
|
|
33
|
+
provisionLater(root);
|
|
34
|
+
// Miss against the cached set must re-scan disk and find it — no restart.
|
|
35
|
+
strict_1.default.equal((0, index_js_1.isProvisionedAccount)(root, LATER_ID), true);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
(0, node_fs_1.rmSync)(root, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
(0, node_test_1.default)("isProvisionedAccount: a truly-absent id still returns false after re-scan", () => {
|
|
42
|
+
(0, index_js_1._resetEnumerationCache)();
|
|
43
|
+
const root = makeFixture();
|
|
44
|
+
try {
|
|
45
|
+
(0, index_js_1.enumerateValidAccountIds)(root); // warm
|
|
46
|
+
const bogus = "00000000-0000-0000-0000-000000000000";
|
|
47
|
+
strict_1.default.equal((0, index_js_1.isProvisionedAccount)(root, bogus), false);
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
(0, node_fs_1.rmSync)(root, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
(0, node_test_1.default)("isProvisionedAccount: a warmed hit returns true without re-scanning", () => {
|
|
54
|
+
(0, index_js_1._resetEnumerationCache)();
|
|
55
|
+
const root = makeFixture();
|
|
56
|
+
try {
|
|
57
|
+
(0, index_js_1.enumerateValidAccountIds)(root); // warm = [BOOT_ID]
|
|
58
|
+
// Provision a second dir AFTER warming.
|
|
59
|
+
provisionLater(root);
|
|
60
|
+
// HIT: BOOT_ID is already in the cached set → true, and the cache must NOT
|
|
61
|
+
// be refreshed (no readdirSync). Proof: the cached set still hides LATER_ID.
|
|
62
|
+
strict_1.default.equal((0, index_js_1.isProvisionedAccount)(root, BOOT_ID), true);
|
|
63
|
+
strict_1.default.deepEqual((0, index_js_1.enumerateValidAccountIds)(root), [BOOT_ID], "a hit must not refresh the cache — LATER_ID must stay hidden");
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
(0, node_fs_1.rmSync)(root, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
(0, node_test_1.default)("isProvisionedAccount: cold cache scans disk and answers", () => {
|
|
70
|
+
(0, index_js_1._resetEnumerationCache)();
|
|
71
|
+
const root = makeFixture();
|
|
72
|
+
try {
|
|
73
|
+
// No warm call — cache is cold. A miss (cold) must scan and answer both ways.
|
|
74
|
+
strict_1.default.equal((0, index_js_1.isProvisionedAccount)(root, BOOT_ID), true);
|
|
75
|
+
strict_1.default.equal((0, index_js_1.isProvisionedAccount)(root, LATER_ID), false);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
(0, node_fs_1.rmSync)(root, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=is-provisioned.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-provisioned.test.js","sourceRoot":"","sources":["../../src/__tests__/is-provisioned.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,23 @@
|
|
|
6
6
|
* be hiding).
|
|
7
7
|
*/
|
|
8
8
|
export declare function enumerateValidAccountIds(accountsDir: string): string[];
|
|
9
|
+
/**
|
|
10
|
+
* Membership test with re-scan-on-miss: is `id` a currently-provisioned account
|
|
11
|
+
* under `accountsDir`?
|
|
12
|
+
*
|
|
13
|
+
* Hit path — `id` is in the cached set — returns true with no I/O (the common
|
|
14
|
+
* case; the cache still serves it). Miss path — `id` is absent from the cached
|
|
15
|
+
* set, or the cache is cold — drops the stale entry and re-scans `accountsDir`
|
|
16
|
+
* once (refreshing the cache) before answering.
|
|
17
|
+
*
|
|
18
|
+
* This closes the created-after-boot gap (Task 1471): a sub-account provisioned
|
|
19
|
+
* by the runtime `account_create` lifecycle tool after a consumer process booted
|
|
20
|
+
* is invisible to that process's boot-time cached set. Without the re-scan, the
|
|
21
|
+
* cross-account resolver rejects the id as not-provisioned even though its dir
|
|
22
|
+
* and `account.json` exist on disk. A single `readdirSync` on the miss finds it;
|
|
23
|
+
* a genuinely-absent id pays the same one scan and correctly returns false.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isProvisionedAccount(accountsDir: string, id: string): boolean;
|
|
9
26
|
/**
|
|
10
27
|
* Returns the single `role:"house"` account UUID under `accountsDir`.
|
|
11
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAwCA;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAgCtE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAO7E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAsBjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqBvE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAS9C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,mCAAmC,GAC3C,SAAS,GACT,oBAAoB,GACpB,UAAU,CAAC;AAEf,MAAM,MAAM,sBAAsB,GAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9C;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,mCAAmC,CAAC;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEN,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,MAAM,EAAE,GAChB,sBAAsB,CAWxB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enumerateValidAccountIds = enumerateValidAccountIds;
|
|
4
|
+
exports.isProvisionedAccount = isProvisionedAccount;
|
|
4
5
|
exports.resolveHouseAccountId = resolveHouseAccountId;
|
|
5
6
|
exports.resolveHouseOrSoleAccountId = resolveHouseOrSoleAccountId;
|
|
6
7
|
exports.getAccountsDirFromEnv = getAccountsDirFromEnv;
|
|
@@ -16,16 +17,27 @@ exports.validateAccountIdEnv = validateAccountIdEnv;
|
|
|
16
17
|
* (`WHERE n.accountId = $accountId`) silently hides leaks from every UI;
|
|
17
18
|
* an unenforced writer can leak indefinitely with zero downstream symptom.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* Consumers of the enumerated set:
|
|
21
|
+
* - The cross-account resolver's injected validity check (the `memory` and
|
|
22
|
+
* `filesystem` MCP plugins) — the check that gates a `targetAccountId`.
|
|
23
|
+
* These call `isProvisionedAccount` (re-scan-on-miss), not the cached list
|
|
24
|
+
* directly, so a sub-account created at runtime is not masked by the boot
|
|
25
|
+
* snapshot (Task 1471).
|
|
26
|
+
* - `resolvePlatformAccountId` (platform/ui/app/lib/whatsapp/platform-account-id.ts)
|
|
27
|
+
* — WhatsApp writer-side helper; loud-throws on zero or multi accounts.
|
|
28
|
+
* - Boot-time env-vs-disk validation (`validateAccountIdEnv`).
|
|
25
29
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
30
|
+
* NOTE: `writeNodeWithEdges` (platform/lib/graph-write/) does NOT enumerate.
|
|
31
|
+
* Its account floor compares `props.accountId` against `process.env.ACCOUNT_ID`
|
|
32
|
+
* (the spawning process's boot-validated id), deliberately staying out of the
|
|
33
|
+
* `node:fs` import chain so the ESM payload bundle emits no `__require("fs")`
|
|
34
|
+
* shim. So the write gate does not share the cache's staleness.
|
|
35
|
+
*
|
|
36
|
+
* Per-process cache keyed on `accountsDir`. The install-time invariant (accounts
|
|
37
|
+
* created only at install) no longer holds: the runtime `account_create`
|
|
38
|
+
* lifecycle tool provisions sub-accounts during a live session. `enumerate…`
|
|
39
|
+
* keeps its cached-list semantics for the hit path; `isProvisionedAccount`
|
|
40
|
+
* re-scans on a miss so a created-after-boot account resolves without restart.
|
|
29
41
|
*/
|
|
30
42
|
const node_fs_1 = require("node:fs");
|
|
31
43
|
const node_path_1 = require("node:path");
|
|
@@ -73,6 +85,31 @@ function enumerateValidAccountIds(accountsDir) {
|
|
|
73
85
|
cache.set(accountsDir, valid);
|
|
74
86
|
return valid;
|
|
75
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Membership test with re-scan-on-miss: is `id` a currently-provisioned account
|
|
90
|
+
* under `accountsDir`?
|
|
91
|
+
*
|
|
92
|
+
* Hit path — `id` is in the cached set — returns true with no I/O (the common
|
|
93
|
+
* case; the cache still serves it). Miss path — `id` is absent from the cached
|
|
94
|
+
* set, or the cache is cold — drops the stale entry and re-scans `accountsDir`
|
|
95
|
+
* once (refreshing the cache) before answering.
|
|
96
|
+
*
|
|
97
|
+
* This closes the created-after-boot gap (Task 1471): a sub-account provisioned
|
|
98
|
+
* by the runtime `account_create` lifecycle tool after a consumer process booted
|
|
99
|
+
* is invisible to that process's boot-time cached set. Without the re-scan, the
|
|
100
|
+
* cross-account resolver rejects the id as not-provisioned even though its dir
|
|
101
|
+
* and `account.json` exist on disk. A single `readdirSync` on the miss finds it;
|
|
102
|
+
* a genuinely-absent id pays the same one scan and correctly returns false.
|
|
103
|
+
*/
|
|
104
|
+
function isProvisionedAccount(accountsDir, id) {
|
|
105
|
+
const cached = cache.get(accountsDir);
|
|
106
|
+
if (cached?.includes(id))
|
|
107
|
+
return true;
|
|
108
|
+
// Miss: `id` is not in the cached set (or the cache is cold). Drop the stale
|
|
109
|
+
// snapshot and re-scan disk once so a real, on-disk account is not masked.
|
|
110
|
+
cache.delete(accountsDir);
|
|
111
|
+
return enumerateValidAccountIds(accountsDir).includes(id);
|
|
112
|
+
}
|
|
76
113
|
/**
|
|
77
114
|
* Returns the single `role:"house"` account UUID under `accountsDir`.
|
|
78
115
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
enumerateValidAccountIds,
|
|
8
|
+
isProvisionedAccount,
|
|
9
|
+
_resetEnumerationCache,
|
|
10
|
+
} from "../index.js";
|
|
11
|
+
|
|
12
|
+
const BOOT_ID = "12345678-9abc-def0-1234-56789abcdef0";
|
|
13
|
+
const LATER_ID = "99999999-aaaa-bbbb-cccc-dddddddddddd";
|
|
14
|
+
|
|
15
|
+
/** One valid account dir (BOOT_ID) that existed at "boot". */
|
|
16
|
+
function makeFixture(): string {
|
|
17
|
+
const root = mkdtempSync(join(tmpdir(), "acct-prov-"));
|
|
18
|
+
mkdirSync(join(root, BOOT_ID));
|
|
19
|
+
writeFileSync(join(root, BOOT_ID, "account.json"), JSON.stringify({ id: BOOT_ID }));
|
|
20
|
+
return root;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Provision a second account dir on disk AFTER boot (simulates account_create). */
|
|
24
|
+
function provisionLater(root: string): void {
|
|
25
|
+
mkdirSync(join(root, LATER_ID));
|
|
26
|
+
writeFileSync(join(root, LATER_ID, "account.json"), JSON.stringify({ id: LATER_ID }));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test("isProvisionedAccount: a created-after-boot id resolves via re-scan on miss", () => {
|
|
30
|
+
_resetEnumerationCache();
|
|
31
|
+
const root = makeFixture();
|
|
32
|
+
try {
|
|
33
|
+
// Warm the cache at "boot" — only BOOT_ID is present.
|
|
34
|
+
assert.deepEqual(enumerateValidAccountIds(root), [BOOT_ID]);
|
|
35
|
+
// A sub-account is provisioned after the snapshot.
|
|
36
|
+
provisionLater(root);
|
|
37
|
+
// Miss against the cached set must re-scan disk and find it — no restart.
|
|
38
|
+
assert.equal(isProvisionedAccount(root, LATER_ID), true);
|
|
39
|
+
} finally {
|
|
40
|
+
rmSync(root, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("isProvisionedAccount: a truly-absent id still returns false after re-scan", () => {
|
|
45
|
+
_resetEnumerationCache();
|
|
46
|
+
const root = makeFixture();
|
|
47
|
+
try {
|
|
48
|
+
enumerateValidAccountIds(root); // warm
|
|
49
|
+
const bogus = "00000000-0000-0000-0000-000000000000";
|
|
50
|
+
assert.equal(isProvisionedAccount(root, bogus), false);
|
|
51
|
+
} finally {
|
|
52
|
+
rmSync(root, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("isProvisionedAccount: a warmed hit returns true without re-scanning", () => {
|
|
57
|
+
_resetEnumerationCache();
|
|
58
|
+
const root = makeFixture();
|
|
59
|
+
try {
|
|
60
|
+
enumerateValidAccountIds(root); // warm = [BOOT_ID]
|
|
61
|
+
// Provision a second dir AFTER warming.
|
|
62
|
+
provisionLater(root);
|
|
63
|
+
// HIT: BOOT_ID is already in the cached set → true, and the cache must NOT
|
|
64
|
+
// be refreshed (no readdirSync). Proof: the cached set still hides LATER_ID.
|
|
65
|
+
assert.equal(isProvisionedAccount(root, BOOT_ID), true);
|
|
66
|
+
assert.deepEqual(
|
|
67
|
+
enumerateValidAccountIds(root),
|
|
68
|
+
[BOOT_ID],
|
|
69
|
+
"a hit must not refresh the cache — LATER_ID must stay hidden",
|
|
70
|
+
);
|
|
71
|
+
} finally {
|
|
72
|
+
rmSync(root, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("isProvisionedAccount: cold cache scans disk and answers", () => {
|
|
77
|
+
_resetEnumerationCache();
|
|
78
|
+
const root = makeFixture();
|
|
79
|
+
try {
|
|
80
|
+
// No warm call — cache is cold. A miss (cold) must scan and answer both ways.
|
|
81
|
+
assert.equal(isProvisionedAccount(root, BOOT_ID), true);
|
|
82
|
+
assert.equal(isProvisionedAccount(root, LATER_ID), false);
|
|
83
|
+
} finally {
|
|
84
|
+
rmSync(root, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
});
|
|
@@ -8,16 +8,27 @@
|
|
|
8
8
|
* (`WHERE n.accountId = $accountId`) silently hides leaks from every UI;
|
|
9
9
|
* an unenforced writer can leak indefinitely with zero downstream symptom.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
11
|
+
* Consumers of the enumerated set:
|
|
12
|
+
* - The cross-account resolver's injected validity check (the `memory` and
|
|
13
|
+
* `filesystem` MCP plugins) — the check that gates a `targetAccountId`.
|
|
14
|
+
* These call `isProvisionedAccount` (re-scan-on-miss), not the cached list
|
|
15
|
+
* directly, so a sub-account created at runtime is not masked by the boot
|
|
16
|
+
* snapshot (Task 1471).
|
|
17
|
+
* - `resolvePlatformAccountId` (platform/ui/app/lib/whatsapp/platform-account-id.ts)
|
|
18
|
+
* — WhatsApp writer-side helper; loud-throws on zero or multi accounts.
|
|
19
|
+
* - Boot-time env-vs-disk validation (`validateAccountIdEnv`).
|
|
17
20
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* NOTE: `writeNodeWithEdges` (platform/lib/graph-write/) does NOT enumerate.
|
|
22
|
+
* Its account floor compares `props.accountId` against `process.env.ACCOUNT_ID`
|
|
23
|
+
* (the spawning process's boot-validated id), deliberately staying out of the
|
|
24
|
+
* `node:fs` import chain so the ESM payload bundle emits no `__require("fs")`
|
|
25
|
+
* shim. So the write gate does not share the cache's staleness.
|
|
26
|
+
*
|
|
27
|
+
* Per-process cache keyed on `accountsDir`. The install-time invariant (accounts
|
|
28
|
+
* created only at install) no longer holds: the runtime `account_create`
|
|
29
|
+
* lifecycle tool provisions sub-accounts during a live session. `enumerate…`
|
|
30
|
+
* keeps its cached-list semantics for the hit path; `isProvisionedAccount`
|
|
31
|
+
* re-scans on a miss so a created-after-boot account resolves without restart.
|
|
21
32
|
*/
|
|
22
33
|
import { readdirSync, readFileSync } from "node:fs";
|
|
23
34
|
import { resolve } from "node:path";
|
|
@@ -68,6 +79,31 @@ export function enumerateValidAccountIds(accountsDir: string): string[] {
|
|
|
68
79
|
return valid;
|
|
69
80
|
}
|
|
70
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Membership test with re-scan-on-miss: is `id` a currently-provisioned account
|
|
84
|
+
* under `accountsDir`?
|
|
85
|
+
*
|
|
86
|
+
* Hit path — `id` is in the cached set — returns true with no I/O (the common
|
|
87
|
+
* case; the cache still serves it). Miss path — `id` is absent from the cached
|
|
88
|
+
* set, or the cache is cold — drops the stale entry and re-scans `accountsDir`
|
|
89
|
+
* once (refreshing the cache) before answering.
|
|
90
|
+
*
|
|
91
|
+
* This closes the created-after-boot gap (Task 1471): a sub-account provisioned
|
|
92
|
+
* by the runtime `account_create` lifecycle tool after a consumer process booted
|
|
93
|
+
* is invisible to that process's boot-time cached set. Without the re-scan, the
|
|
94
|
+
* cross-account resolver rejects the id as not-provisioned even though its dir
|
|
95
|
+
* and `account.json` exist on disk. A single `readdirSync` on the miss finds it;
|
|
96
|
+
* a genuinely-absent id pays the same one scan and correctly returns false.
|
|
97
|
+
*/
|
|
98
|
+
export function isProvisionedAccount(accountsDir: string, id: string): boolean {
|
|
99
|
+
const cached = cache.get(accountsDir);
|
|
100
|
+
if (cached?.includes(id)) return true;
|
|
101
|
+
// Miss: `id` is not in the cached set (or the cache is cold). Drop the stale
|
|
102
|
+
// snapshot and re-scan disk once so a real, on-disk account is not masked.
|
|
103
|
+
cache.delete(accountsDir);
|
|
104
|
+
return enumerateValidAccountIds(accountsDir).includes(id);
|
|
105
|
+
}
|
|
106
|
+
|
|
71
107
|
/**
|
|
72
108
|
* Returns the single `role:"house"` account UUID under `accountsDir`.
|
|
73
109
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type EffectiveAccount = {
|
|
2
2
|
accountId: string;
|
|
3
3
|
} | {
|
|
4
|
-
reject: "cross-account-denied" | "cross-account-invalid-target";
|
|
4
|
+
reject: "cross-account-denied" | "cross-account-invalid-target" | "cross-account-target-not-provisioned";
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
7
|
* Resolve the account a call acts on. Fail-closed: only a house-scoped session
|
|
@@ -10,15 +10,24 @@ export type EffectiveAccount = {
|
|
|
10
10
|
* downgraded to its own account.
|
|
11
11
|
*
|
|
12
12
|
* `isValidAccountId` is injected (required, no default): the UI passes its
|
|
13
|
-
* fs-backed `isValidAccountId
|
|
14
|
-
* `
|
|
15
|
-
* module stay pure.
|
|
13
|
+
* fs-backed `isValidAccountId` (reads disk fresh every call); the `memory` and
|
|
14
|
+
* `filesystem` plugins pass `isProvisionedAccount` (cached-hit, re-scan-on-miss).
|
|
15
|
+
* Keeping validity injected is what lets this module stay pure.
|
|
16
|
+
*
|
|
17
|
+
* `notProvisionedReason` names the reject emitted when the injected check fails.
|
|
18
|
+
* It defaults to `cross-account-invalid-target` (the UI path, byte-identical to
|
|
19
|
+
* the 1440 landing). The MCP plugins pass `cross-account-target-not-provisioned`
|
|
20
|
+
* because their injected check re-scans disk on a miss (Task 1471) — so a false
|
|
21
|
+
* from it means the id is genuinely not on disk, distinct from a stale-cache
|
|
22
|
+
* miss (which no longer rejects). The distinct reason lets an operator tell a
|
|
23
|
+
* wrong/typo id from the (now-eliminated) created-after-boot case in the
|
|
24
|
+
* `[xacct] op=call … reason=` line.
|
|
16
25
|
*/
|
|
17
26
|
export declare function resolveEffectiveAccountCore(input: {
|
|
18
27
|
ownAccountId: string;
|
|
19
28
|
houseScope: string | null;
|
|
20
29
|
targetAccountId?: string | null;
|
|
21
|
-
}, isValidAccountId: (id: string) => boolean): EffectiveAccount;
|
|
30
|
+
}, isValidAccountId: (id: string) => boolean, notProvisionedReason?: "cross-account-invalid-target" | "cross-account-target-not-provisioned"): EffectiveAccount;
|
|
22
31
|
/**
|
|
23
32
|
* Boot-reader that consumers import to learn their house scope from the spawn
|
|
24
33
|
* env. An empty value reads as null — a non-house session carries no scope.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,gBAAgB,GACxB;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GACrB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,gBAAgB,GACxB;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GACrB;IACE,MAAM,EACF,sBAAsB,GACtB,8BAA8B,GAC9B,sCAAsC,CAAC;CAC5C,CAAC;AAEN;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC3F,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,EACzC,oBAAoB,GAChB,8BAA8B,GAC9B,sCAAuE,GAC1E,gBAAgB,CAMlB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,IAAI,CAEvF"}
|
|
@@ -9,18 +9,27 @@ exports.readHouseAdminScope = readHouseAdminScope;
|
|
|
9
9
|
* downgraded to its own account.
|
|
10
10
|
*
|
|
11
11
|
* `isValidAccountId` is injected (required, no default): the UI passes its
|
|
12
|
-
* fs-backed `isValidAccountId
|
|
13
|
-
* `
|
|
14
|
-
* module stay pure.
|
|
12
|
+
* fs-backed `isValidAccountId` (reads disk fresh every call); the `memory` and
|
|
13
|
+
* `filesystem` plugins pass `isProvisionedAccount` (cached-hit, re-scan-on-miss).
|
|
14
|
+
* Keeping validity injected is what lets this module stay pure.
|
|
15
|
+
*
|
|
16
|
+
* `notProvisionedReason` names the reject emitted when the injected check fails.
|
|
17
|
+
* It defaults to `cross-account-invalid-target` (the UI path, byte-identical to
|
|
18
|
+
* the 1440 landing). The MCP plugins pass `cross-account-target-not-provisioned`
|
|
19
|
+
* because their injected check re-scans disk on a miss (Task 1471) — so a false
|
|
20
|
+
* from it means the id is genuinely not on disk, distinct from a stale-cache
|
|
21
|
+
* miss (which no longer rejects). The distinct reason lets an operator tell a
|
|
22
|
+
* wrong/typo id from the (now-eliminated) created-after-boot case in the
|
|
23
|
+
* `[xacct] op=call … reason=` line.
|
|
15
24
|
*/
|
|
16
|
-
function resolveEffectiveAccountCore(input, isValidAccountId) {
|
|
25
|
+
function resolveEffectiveAccountCore(input, isValidAccountId, notProvisionedReason = "cross-account-invalid-target") {
|
|
17
26
|
const { ownAccountId, houseScope, targetAccountId } = input;
|
|
18
27
|
if (!targetAccountId)
|
|
19
28
|
return { accountId: ownAccountId };
|
|
20
29
|
if (!houseScope)
|
|
21
30
|
return { reject: "cross-account-denied" };
|
|
22
31
|
if (!isValidAccountId(targetAccountId))
|
|
23
|
-
return { reject:
|
|
32
|
+
return { reject: notProvisionedReason };
|
|
24
33
|
return { accountId: targetAccountId };
|
|
25
34
|
}
|
|
26
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAuCA,kEAYC;AAMD,kDAEC;AAxCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,2BAA2B,CACzC,KAA2F,EAC3F,gBAAyC,EACzC,uBAE6C,8BAA8B;IAE3E,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IAC5D,IAAI,CAAC,eAAe;QAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IACzD,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC3D,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAChF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,OAAO,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC"}
|