@rubytech/create-realagent 1.0.840 → 1.0.843

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 (58) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.d.ts +2 -0
  3. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.d.ts.map +1 -0
  4. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.js +88 -0
  5. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.js.map +1 -0
  6. package/payload/platform/lib/account-enumeration/dist/index.d.ts +23 -0
  7. package/payload/platform/lib/account-enumeration/dist/index.d.ts.map +1 -0
  8. package/payload/platform/lib/account-enumeration/dist/index.js +96 -0
  9. package/payload/platform/lib/account-enumeration/dist/index.js.map +1 -0
  10. package/payload/platform/lib/account-enumeration/src/__tests__/enumerate.test.ts +94 -0
  11. package/payload/platform/lib/account-enumeration/src/index.ts +96 -0
  12. package/payload/platform/lib/account-enumeration/tsconfig.json +8 -0
  13. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.d.ts +2 -0
  14. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.d.ts.map +1 -0
  15. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js +165 -0
  16. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js.map +1 -0
  17. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +15 -5
  18. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -1
  19. package/payload/platform/lib/graph-write/dist/index.d.ts +12 -0
  20. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  21. package/payload/platform/lib/graph-write/dist/index.js +25 -0
  22. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  23. package/payload/platform/lib/graph-write/src/__tests__/account-id-gate.test.ts +189 -0
  24. package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +16 -5
  25. package/payload/platform/lib/graph-write/src/index.ts +45 -1
  26. package/payload/platform/package.json +2 -2
  27. package/payload/platform/plugins/admin/PLUGIN.md +2 -1
  28. package/payload/platform/plugins/admin/mcp/dist/index.js +133 -1
  29. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  30. package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +18 -19
  31. package/payload/platform/plugins/docs/references/attachments.md +2 -2
  32. package/payload/platform/plugins/docs/references/internals.md +1 -1
  33. package/payload/platform/plugins/docs/references/plugins-guide.md +10 -0
  34. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  35. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
  36. package/payload/platform/templates/agents/admin/IDENTITY.md +4 -0
  37. package/payload/server/adminuser-self-heal-RY4NFCI7.js +45 -0
  38. package/payload/server/chunk-2YG3AYAH.js +1508 -0
  39. package/payload/server/chunk-7DFOKDNM.js +2098 -0
  40. package/payload/server/chunk-DTWW35TK.js +667 -0
  41. package/payload/server/chunk-HTYXRFT6.js +727 -0
  42. package/payload/server/chunk-NPVEOM3D.js +1508 -0
  43. package/payload/server/chunk-OLP7LZDW.js +10119 -0
  44. package/payload/server/chunk-QGM4M3NI.js +37 -0
  45. package/payload/server/chunk-S27QCBFQ.js +10071 -0
  46. package/payload/server/chunk-TS6CKCGU.js +727 -0
  47. package/payload/server/chunk-XECKT3YB.js +10071 -0
  48. package/payload/server/client-pool-2WQ2Q3TF.js +32 -0
  49. package/payload/server/client-pool-SMWCZMZG.js +32 -0
  50. package/payload/server/cloudflare-task-tracker-NQK7A2EQ.js +20 -0
  51. package/payload/server/cloudflare-task-tracker-O4ZA4TAS.js +20 -0
  52. package/payload/server/cloudflare-task-tracker-XFGXO7ZV.js +20 -0
  53. package/payload/server/maxy-edge.js +2 -2
  54. package/payload/server/public/assets/{admin-D678VwpH.js → admin-CvwOOG4D.js} +1 -1
  55. package/payload/server/public/assets/{public-C7mCgRX0.js → public-Br9YjNs_.js} +2 -2
  56. package/payload/server/public/index.html +1 -1
  57. package/payload/server/public/public.html +1 -1
  58. package/payload/server/server.js +65 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-realagent",
3
- "version": "1.0.840",
3
+ "version": "1.0.843",
4
4
  "description": "Install Real Agent — Built for agents. By agents.",
5
5
  "bin": {
6
6
  "create-realagent": "./dist/index.js"
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=enumerate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enumerate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/enumerate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
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
+ function makeFixture() {
13
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "acct-enum-"));
14
+ // (a) non-UUID dir → excluded.
15
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "not-a-uuid"));
16
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "not-a-uuid", "account.json"), "{}");
17
+ // (b) UUID dir, no account.json → excluded.
18
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "11111111-2222-3333-4444-555555555555"));
19
+ // (c) UUID dir, unparseable account.json → excluded (over-prune doctrine).
20
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"));
21
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "account.json"), "{ broken json");
22
+ // (d) UUID dir, parseable account.json → included.
23
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, "12345678-9abc-def0-1234-56789abcdef0"));
24
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, "12345678-9abc-def0-1234-56789abcdef0", "account.json"), JSON.stringify({ id: "12345678-9abc-def0-1234-56789abcdef0" }));
25
+ return root;
26
+ }
27
+ (0, node_test_1.default)("enumerateValidAccountIds returns only UUID dirs with parseable account.json", () => {
28
+ (0, index_js_1._resetEnumerationCache)();
29
+ const root = makeFixture();
30
+ try {
31
+ const result = (0, index_js_1.enumerateValidAccountIds)(root);
32
+ strict_1.default.deepEqual(result, ["12345678-9abc-def0-1234-56789abcdef0"]);
33
+ }
34
+ finally {
35
+ (0, node_fs_1.rmSync)(root, { recursive: true });
36
+ }
37
+ });
38
+ (0, node_test_1.default)("enumerateValidAccountIds returns [] when accountsDir does not exist", () => {
39
+ (0, index_js_1._resetEnumerationCache)();
40
+ const ghost = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "acct-enum-does-not-exist-" + Date.now());
41
+ strict_1.default.deepEqual((0, index_js_1.enumerateValidAccountIds)(ghost), []);
42
+ });
43
+ (0, node_test_1.default)("enumerateValidAccountIds caches per accountsDir; reset re-reads", () => {
44
+ (0, index_js_1._resetEnumerationCache)();
45
+ const root = makeFixture();
46
+ try {
47
+ const first = (0, index_js_1.enumerateValidAccountIds)(root);
48
+ // Add a second valid dir AFTER first call; cached call must NOT see it.
49
+ const newId = "99999999-aaaa-bbbb-cccc-dddddddddddd";
50
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(root, newId));
51
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(root, newId, "account.json"), "{}");
52
+ const cached = (0, index_js_1.enumerateValidAccountIds)(root);
53
+ strict_1.default.deepEqual(cached, first, "cache should hide the newly-added dir");
54
+ (0, index_js_1._resetEnumerationCache)();
55
+ const fresh = (0, index_js_1.enumerateValidAccountIds)(root);
56
+ strict_1.default.equal(fresh.length, 2);
57
+ strict_1.default.ok(fresh.includes(newId));
58
+ }
59
+ finally {
60
+ (0, node_fs_1.rmSync)(root, { recursive: true });
61
+ }
62
+ });
63
+ (0, node_test_1.default)("getAccountsDirFromEnv throws when MAXY_PLATFORM_ROOT is unset", () => {
64
+ const saved = process.env.MAXY_PLATFORM_ROOT;
65
+ delete process.env.MAXY_PLATFORM_ROOT;
66
+ try {
67
+ strict_1.default.throws(() => (0, index_js_1.getAccountsDirFromEnv)(), /MAXY_PLATFORM_ROOT not set/);
68
+ }
69
+ finally {
70
+ if (saved !== undefined)
71
+ process.env.MAXY_PLATFORM_ROOT = saved;
72
+ }
73
+ });
74
+ (0, node_test_1.default)("getAccountsDirFromEnv resolves to ${root}/../data/accounts when set", () => {
75
+ const saved = process.env.MAXY_PLATFORM_ROOT;
76
+ process.env.MAXY_PLATFORM_ROOT = "/tmp/fake-root/platform";
77
+ try {
78
+ const result = (0, index_js_1.getAccountsDirFromEnv)();
79
+ strict_1.default.equal(result, (0, node_path_1.resolve)("/tmp/fake-root/platform", "..", "data/accounts"));
80
+ }
81
+ finally {
82
+ if (saved !== undefined)
83
+ process.env.MAXY_PLATFORM_ROOT = saved;
84
+ else
85
+ delete process.env.MAXY_PLATFORM_ROOT;
86
+ }
87
+ });
88
+ //# sourceMappingURL=enumerate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enumerate.test.js","sourceRoot":"","sources":["../../src/__tests__/enumerate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Returns the list of valid account UUIDs found under `accountsDir`. A dir is
3
+ * "valid" iff its name is a UUID AND it contains a parseable `account.json`.
4
+ * Corruption-discipline: a present-but-unparseable account.json EXCLUDES the
5
+ * dir (over-prune one suspect account beats under-prune the leak it might
6
+ * be hiding).
7
+ */
8
+ export declare function enumerateValidAccountIds(accountsDir: string): string[];
9
+ /**
10
+ * Resolves the canonical accounts dir from `MAXY_PLATFORM_ROOT`. Mirrors the
11
+ * pattern at platform/ui/app/lib/claude-agent/account.ts:9
12
+ * (`ACCOUNTS_DIR = resolve(PLATFORM_ROOT, "..", "data/accounts")`).
13
+ *
14
+ * Loud-throws when the env var is unset — graph-write's gate must not fall
15
+ * open silently.
16
+ */
17
+ export declare function getAccountsDirFromEnv(): string;
18
+ /**
19
+ * Test-only cache reset. Production callers must not invoke this — the cache
20
+ * is a deliberate boot-time invariant (see module doc).
21
+ */
22
+ export declare function _resetEnumerationCache(): void;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAgCtE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAS9C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enumerateValidAccountIds = enumerateValidAccountIds;
4
+ exports.getAccountsDirFromEnv = getAccountsDirFromEnv;
5
+ exports._resetEnumerationCache = _resetEnumerationCache;
6
+ /**
7
+ * account-enumeration — single source of truth for "which accountIds are
8
+ * provisioned on disk for this install?".
9
+ *
10
+ * Doctrine — `.docs/neo4j.md` "Account isolation invariant": every writer
11
+ * that stamps `n.accountId` must verify the value against
12
+ * `${DATA_ROOT}/accounts/<id>/account.json` before write. Read-side scoping
13
+ * (`WHERE n.accountId = $accountId`) silently hides leaks from every UI;
14
+ * an unenforced writer can leak indefinitely with zero downstream symptom.
15
+ *
16
+ * Two consumers:
17
+ * 1. `writeNodeWithEdges` (platform/lib/graph-write/) — central write-time
18
+ * floor; rejects any write whose `props.accountId` is not in the set
19
+ * returned here, unless `createdBy.agent === 'system'` (bootstrap).
20
+ * 2. `resolvePlatformAccountId` (platform/ui/app/lib/whatsapp/platform-account-id.ts)
21
+ * — WhatsApp writer-side helper; loud-throws on zero or multi accounts.
22
+ *
23
+ * Per-process cache keyed on `accountsDir` — Phase 0 invariant has accounts
24
+ * created at install time, so adding/removing accounts requires a service
25
+ * restart anyway.
26
+ */
27
+ const node_fs_1 = require("node:fs");
28
+ const node_path_1 = require("node:path");
29
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
30
+ const cache = new Map();
31
+ /**
32
+ * Returns the list of valid account UUIDs found under `accountsDir`. A dir is
33
+ * "valid" iff its name is a UUID AND it contains a parseable `account.json`.
34
+ * Corruption-discipline: a present-but-unparseable account.json EXCLUDES the
35
+ * dir (over-prune one suspect account beats under-prune the leak it might
36
+ * be hiding).
37
+ */
38
+ function enumerateValidAccountIds(accountsDir) {
39
+ const cached = cache.get(accountsDir);
40
+ if (cached !== undefined)
41
+ return cached;
42
+ let names;
43
+ try {
44
+ names = (0, node_fs_1.readdirSync)(accountsDir);
45
+ }
46
+ catch (err) {
47
+ if (err.code === "ENOENT") {
48
+ cache.set(accountsDir, []);
49
+ return [];
50
+ }
51
+ throw err;
52
+ }
53
+ const valid = [];
54
+ for (const name of names) {
55
+ if (!UUID_RE.test(name))
56
+ continue;
57
+ const configPath = (0, node_path_1.resolve)(accountsDir, name, "account.json");
58
+ try {
59
+ JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
60
+ valid.push(name);
61
+ }
62
+ catch (err) {
63
+ const code = err.code;
64
+ if (code === "ENOENT")
65
+ continue;
66
+ // SyntaxError (parse failure) and other read errors fall through:
67
+ // exclude this dir, try the next.
68
+ }
69
+ }
70
+ cache.set(accountsDir, valid);
71
+ return valid;
72
+ }
73
+ /**
74
+ * Resolves the canonical accounts dir from `MAXY_PLATFORM_ROOT`. Mirrors the
75
+ * pattern at platform/ui/app/lib/claude-agent/account.ts:9
76
+ * (`ACCOUNTS_DIR = resolve(PLATFORM_ROOT, "..", "data/accounts")`).
77
+ *
78
+ * Loud-throws when the env var is unset — graph-write's gate must not fall
79
+ * open silently.
80
+ */
81
+ function getAccountsDirFromEnv() {
82
+ const root = process.env.MAXY_PLATFORM_ROOT;
83
+ if (!root) {
84
+ throw new Error("[graph-write] MAXY_PLATFORM_ROOT not set — cannot enforce accountId gate. " +
85
+ "Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly.");
86
+ }
87
+ return (0, node_path_1.resolve)(root, "..", "data/accounts");
88
+ }
89
+ /**
90
+ * Test-only cache reset. Production callers must not invoke this — the cache
91
+ * is a deliberate boot-time invariant (see module doc).
92
+ */
93
+ function _resetEnumerationCache() {
94
+ cache.clear();
95
+ }
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAoCA,4DAgCC;AAUD,sDASC;AAMD,wDAEC;AA/FD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qCAAoD;AACpD,yCAAoC;AAEpC,MAAM,OAAO,GACX,iEAAiE,CAAC;AAEpE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;AAE1C;;;;;;GAMG;AACH,SAAgB,wBAAwB,CAAC,WAAmB;IAC1D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExC,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,IAAA,qBAAW,EAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC3B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,MAAM,UAAU,GAAG,IAAA,mBAAO,EAAC,WAAW,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAC9D,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;YACjD,IAAI,IAAI,KAAK,QAAQ;gBAAE,SAAS;YAChC,kEAAkE;YAClE,kCAAkC;QACpC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,qBAAqB;IACnC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,4EAA4E;YAC1E,kFAAkF,CACrF,CAAC;IACJ,CAAC;IACD,OAAO,IAAA,mBAAO,EAAC,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAgB,sBAAsB;IACpC,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,94 @@
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, resolve } from "node:path";
6
+ import {
7
+ enumerateValidAccountIds,
8
+ getAccountsDirFromEnv,
9
+ _resetEnumerationCache,
10
+ } from "../index.js";
11
+
12
+ function makeFixture(): string {
13
+ const root = mkdtempSync(join(tmpdir(), "acct-enum-"));
14
+ // (a) non-UUID dir → excluded.
15
+ mkdirSync(join(root, "not-a-uuid"));
16
+ writeFileSync(join(root, "not-a-uuid", "account.json"), "{}");
17
+ // (b) UUID dir, no account.json → excluded.
18
+ mkdirSync(join(root, "11111111-2222-3333-4444-555555555555"));
19
+ // (c) UUID dir, unparseable account.json → excluded (over-prune doctrine).
20
+ mkdirSync(join(root, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"));
21
+ writeFileSync(
22
+ join(root, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "account.json"),
23
+ "{ broken json",
24
+ );
25
+ // (d) UUID dir, parseable account.json → included.
26
+ mkdirSync(join(root, "12345678-9abc-def0-1234-56789abcdef0"));
27
+ writeFileSync(
28
+ join(root, "12345678-9abc-def0-1234-56789abcdef0", "account.json"),
29
+ JSON.stringify({ id: "12345678-9abc-def0-1234-56789abcdef0" }),
30
+ );
31
+ return root;
32
+ }
33
+
34
+ test("enumerateValidAccountIds returns only UUID dirs with parseable account.json", () => {
35
+ _resetEnumerationCache();
36
+ const root = makeFixture();
37
+ try {
38
+ const result = enumerateValidAccountIds(root);
39
+ assert.deepEqual(result, ["12345678-9abc-def0-1234-56789abcdef0"]);
40
+ } finally {
41
+ rmSync(root, { recursive: true });
42
+ }
43
+ });
44
+
45
+ test("enumerateValidAccountIds returns [] when accountsDir does not exist", () => {
46
+ _resetEnumerationCache();
47
+ const ghost = join(tmpdir(), "acct-enum-does-not-exist-" + Date.now());
48
+ assert.deepEqual(enumerateValidAccountIds(ghost), []);
49
+ });
50
+
51
+ test("enumerateValidAccountIds caches per accountsDir; reset re-reads", () => {
52
+ _resetEnumerationCache();
53
+ const root = makeFixture();
54
+ try {
55
+ const first = enumerateValidAccountIds(root);
56
+ // Add a second valid dir AFTER first call; cached call must NOT see it.
57
+ const newId = "99999999-aaaa-bbbb-cccc-dddddddddddd";
58
+ mkdirSync(join(root, newId));
59
+ writeFileSync(join(root, newId, "account.json"), "{}");
60
+ const cached = enumerateValidAccountIds(root);
61
+ assert.deepEqual(cached, first, "cache should hide the newly-added dir");
62
+ _resetEnumerationCache();
63
+ const fresh = enumerateValidAccountIds(root);
64
+ assert.equal(fresh.length, 2);
65
+ assert.ok(fresh.includes(newId));
66
+ } finally {
67
+ rmSync(root, { recursive: true });
68
+ }
69
+ });
70
+
71
+ test("getAccountsDirFromEnv throws when MAXY_PLATFORM_ROOT is unset", () => {
72
+ const saved = process.env.MAXY_PLATFORM_ROOT;
73
+ delete process.env.MAXY_PLATFORM_ROOT;
74
+ try {
75
+ assert.throws(
76
+ () => getAccountsDirFromEnv(),
77
+ /MAXY_PLATFORM_ROOT not set/,
78
+ );
79
+ } finally {
80
+ if (saved !== undefined) process.env.MAXY_PLATFORM_ROOT = saved;
81
+ }
82
+ });
83
+
84
+ test("getAccountsDirFromEnv resolves to ${root}/../data/accounts when set", () => {
85
+ const saved = process.env.MAXY_PLATFORM_ROOT;
86
+ process.env.MAXY_PLATFORM_ROOT = "/tmp/fake-root/platform";
87
+ try {
88
+ const result = getAccountsDirFromEnv();
89
+ assert.equal(result, resolve("/tmp/fake-root/platform", "..", "data/accounts"));
90
+ } finally {
91
+ if (saved !== undefined) process.env.MAXY_PLATFORM_ROOT = saved;
92
+ else delete process.env.MAXY_PLATFORM_ROOT;
93
+ }
94
+ });
@@ -0,0 +1,96 @@
1
+ /**
2
+ * account-enumeration — single source of truth for "which accountIds are
3
+ * provisioned on disk for this install?".
4
+ *
5
+ * Doctrine — `.docs/neo4j.md` "Account isolation invariant": every writer
6
+ * that stamps `n.accountId` must verify the value against
7
+ * `${DATA_ROOT}/accounts/<id>/account.json` before write. Read-side scoping
8
+ * (`WHERE n.accountId = $accountId`) silently hides leaks from every UI;
9
+ * an unenforced writer can leak indefinitely with zero downstream symptom.
10
+ *
11
+ * Two consumers:
12
+ * 1. `writeNodeWithEdges` (platform/lib/graph-write/) — central write-time
13
+ * floor; rejects any write whose `props.accountId` is not in the set
14
+ * returned here, unless `createdBy.agent === 'system'` (bootstrap).
15
+ * 2. `resolvePlatformAccountId` (platform/ui/app/lib/whatsapp/platform-account-id.ts)
16
+ * — WhatsApp writer-side helper; loud-throws on zero or multi accounts.
17
+ *
18
+ * Per-process cache keyed on `accountsDir` — Phase 0 invariant has accounts
19
+ * created at install time, so adding/removing accounts requires a service
20
+ * restart anyway.
21
+ */
22
+ import { readdirSync, readFileSync } from "node:fs";
23
+ import { resolve } from "node:path";
24
+
25
+ const UUID_RE =
26
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27
+
28
+ const cache = new Map<string, string[]>();
29
+
30
+ /**
31
+ * Returns the list of valid account UUIDs found under `accountsDir`. A dir is
32
+ * "valid" iff its name is a UUID AND it contains a parseable `account.json`.
33
+ * Corruption-discipline: a present-but-unparseable account.json EXCLUDES the
34
+ * dir (over-prune one suspect account beats under-prune the leak it might
35
+ * be hiding).
36
+ */
37
+ export function enumerateValidAccountIds(accountsDir: string): string[] {
38
+ const cached = cache.get(accountsDir);
39
+ if (cached !== undefined) return cached;
40
+
41
+ let names: string[];
42
+ try {
43
+ names = readdirSync(accountsDir);
44
+ } catch (err) {
45
+ if ((err as NodeJS.ErrnoException).code === "ENOENT") {
46
+ cache.set(accountsDir, []);
47
+ return [];
48
+ }
49
+ throw err;
50
+ }
51
+
52
+ const valid: string[] = [];
53
+ for (const name of names) {
54
+ if (!UUID_RE.test(name)) continue;
55
+ const configPath = resolve(accountsDir, name, "account.json");
56
+ try {
57
+ JSON.parse(readFileSync(configPath, "utf-8"));
58
+ valid.push(name);
59
+ } catch (err) {
60
+ const code = (err as NodeJS.ErrnoException).code;
61
+ if (code === "ENOENT") continue;
62
+ // SyntaxError (parse failure) and other read errors fall through:
63
+ // exclude this dir, try the next.
64
+ }
65
+ }
66
+
67
+ cache.set(accountsDir, valid);
68
+ return valid;
69
+ }
70
+
71
+ /**
72
+ * Resolves the canonical accounts dir from `MAXY_PLATFORM_ROOT`. Mirrors the
73
+ * pattern at platform/ui/app/lib/claude-agent/account.ts:9
74
+ * (`ACCOUNTS_DIR = resolve(PLATFORM_ROOT, "..", "data/accounts")`).
75
+ *
76
+ * Loud-throws when the env var is unset — graph-write's gate must not fall
77
+ * open silently.
78
+ */
79
+ export function getAccountsDirFromEnv(): string {
80
+ const root = process.env.MAXY_PLATFORM_ROOT;
81
+ if (!root) {
82
+ throw new Error(
83
+ "[graph-write] MAXY_PLATFORM_ROOT not set — cannot enforce accountId gate. " +
84
+ "Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly.",
85
+ );
86
+ }
87
+ return resolve(root, "..", "data/accounts");
88
+ }
89
+
90
+ /**
91
+ * Test-only cache reset. Production callers must not invoke this — the cache
92
+ * is a deliberate boot-time invariant (see module doc).
93
+ */
94
+ export function _resetEnumerationCache(): void {
95
+ cache.clear();
96
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=account-id-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-id-gate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/account-id-gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,165 @@
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 index_js_1 = require("../index.js");
9
+ function makeStubSession(targetId) {
10
+ const tx = {
11
+ async run(cypher, params = {}) {
12
+ if (cypher.includes("RETURN elementId(t) AS id, labels(t) AS labels")) {
13
+ const ids = params.ids ?? [];
14
+ const records = ids
15
+ .filter((id) => id === targetId)
16
+ .map((id) => ({
17
+ get(field) {
18
+ if (field === "id")
19
+ return id;
20
+ if (field === "labels")
21
+ return ["Account"];
22
+ throw new Error(`unknown field ${field}`);
23
+ },
24
+ }));
25
+ return { records };
26
+ }
27
+ if (cypher.includes("CREATE (n:")) {
28
+ return {
29
+ records: [
30
+ {
31
+ get(field) {
32
+ if (field === "nodeId")
33
+ return "new-element-id";
34
+ if (field === "nodeLabels")
35
+ return ["Conversation"];
36
+ throw new Error(`unknown field ${field}`);
37
+ },
38
+ },
39
+ ],
40
+ };
41
+ }
42
+ if (cypher.includes("CREATE (a)-[") || cypher.includes("CREATE (b)-[")) {
43
+ return {
44
+ records: [],
45
+ summary: {
46
+ counters: {
47
+ updates: () => ({ relationshipsCreated: 1 }),
48
+ },
49
+ },
50
+ };
51
+ }
52
+ return { records: [] };
53
+ },
54
+ };
55
+ return {
56
+ async executeWrite(work) {
57
+ return await work(tx);
58
+ },
59
+ };
60
+ }
61
+ const VALID_UUID = "12345678-9abc-def0-1234-56789abcdef0";
62
+ const TARGET_ID = "target-element-id";
63
+ const REL = [
64
+ { type: "PART_OF", direction: "outgoing", targetNodeId: TARGET_ID },
65
+ ];
66
+ function captureStderr() {
67
+ const original = process.stderr.write.bind(process.stderr);
68
+ let buf = "";
69
+ process.stderr.write =
70
+ (chunk) => {
71
+ buf += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
72
+ return true;
73
+ };
74
+ return {
75
+ restore: () => {
76
+ process.stderr.write = original;
77
+ },
78
+ output: () => buf,
79
+ };
80
+ }
81
+ (0, node_test_1.default)("rejects null accountId from non-system writer", async () => {
82
+ const cap = captureStderr();
83
+ try {
84
+ await strict_1.default.rejects(() => (0, index_js_1.writeNodeWithEdges)({
85
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
+ session: makeStubSession(TARGET_ID),
87
+ labels: ["Conversation"],
88
+ props: { accountId: null },
89
+ relationships: REL,
90
+ createdBy: { agent: "test-agent", session: "s" },
91
+ expectedAccountId: VALID_UUID,
92
+ }), /invalid-account-id/);
93
+ cap.restore();
94
+ strict_1.default.match(cap.output(), /\[graph-write\] reject reason=invalid-account-id accountId=missing writer=test-agent\b/);
95
+ }
96
+ finally {
97
+ cap.restore();
98
+ }
99
+ });
100
+ (0, node_test_1.default)("rejects non-UUID accountId from non-system writer", async () => {
101
+ const cap = captureStderr();
102
+ try {
103
+ await strict_1.default.rejects(() => (0, index_js_1.writeNodeWithEdges)({
104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
+ session: makeStubSession(TARGET_ID),
106
+ labels: ["Conversation"],
107
+ props: { accountId: "evil-leak" },
108
+ relationships: REL,
109
+ createdBy: { agent: "test-agent", session: "s" },
110
+ expectedAccountId: VALID_UUID,
111
+ }), /invalid-account-id/);
112
+ cap.restore();
113
+ strict_1.default.match(cap.output(), /\[graph-write\] reject reason=invalid-account-id accountId=evil-lea writer=test-agent\b/);
114
+ }
115
+ finally {
116
+ cap.restore();
117
+ }
118
+ });
119
+ (0, node_test_1.default)("rejects UUID-shape accountId that does not match the expected one", async () => {
120
+ const stranger = "ffffffff-1111-2222-3333-444444444444";
121
+ const cap = captureStderr();
122
+ try {
123
+ await strict_1.default.rejects(() => (0, index_js_1.writeNodeWithEdges)({
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ session: makeStubSession(TARGET_ID),
126
+ labels: ["Conversation"],
127
+ props: { accountId: stranger },
128
+ relationships: REL,
129
+ createdBy: { agent: "test-agent", session: "s" },
130
+ expectedAccountId: VALID_UUID,
131
+ }), /invalid-account-id/);
132
+ cap.restore();
133
+ strict_1.default.match(cap.output(), /\[graph-write\] reject reason=invalid-account-id accountId=ffffffff writer=test-agent\b/);
134
+ }
135
+ finally {
136
+ cap.restore();
137
+ }
138
+ });
139
+ (0, node_test_1.default)("accepts matching accountId from non-system writer", async () => {
140
+ const result = await (0, index_js_1.writeNodeWithEdges)({
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
+ session: makeStubSession(TARGET_ID),
143
+ labels: ["Conversation"],
144
+ props: { accountId: VALID_UUID },
145
+ relationships: REL,
146
+ createdBy: { agent: "test-agent", session: "s" },
147
+ expectedAccountId: VALID_UUID,
148
+ });
149
+ strict_1.default.equal(result.nodeId, "new-element-id");
150
+ strict_1.default.equal(result.edgesCreated, 1);
151
+ });
152
+ (0, node_test_1.default)("system bootstrap exemption: bad accountId still proceeds", async () => {
153
+ const result = await (0, index_js_1.writeNodeWithEdges)({
154
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
155
+ session: makeStubSession(TARGET_ID),
156
+ labels: ["Conversation"],
157
+ // accountId is intentionally wrong; system bootstrap exempts it.
158
+ props: { accountId: "not-a-uuid" },
159
+ relationships: REL,
160
+ createdBy: { agent: "system", source: "writeAdminUserAndPerson" },
161
+ expectedAccountId: VALID_UUID,
162
+ });
163
+ strict_1.default.equal(result.nodeId, "new-element-id");
164
+ });
165
+ //# sourceMappingURL=account-id-gate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-id-gate.test.js","sourceRoot":"","sources":["../../src/__tests__/account-id-gate.test.ts"],"names":[],"mappings":"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"}