@rubytech/create-maxy 1.0.740 → 1.0.741

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 (45) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/brand-templating/dist/index.d.ts +18 -0
  3. package/payload/platform/lib/brand-templating/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/brand-templating/dist/index.js +69 -0
  5. package/payload/platform/lib/brand-templating/dist/index.js.map +1 -0
  6. package/payload/platform/lib/brand-templating/src/index.ts +76 -0
  7. package/payload/platform/lib/brand-templating/tsconfig.json +8 -0
  8. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  9. package/payload/platform/lib/graph-write/dist/index.js +23 -1
  10. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  11. package/payload/platform/lib/graph-write/src/index.ts +27 -4
  12. package/payload/platform/neo4j/schema.cypher +5 -2
  13. package/payload/platform/package.json +2 -2
  14. package/payload/platform/plugins/admin/mcp/dist/index.js +6 -1
  15. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  16. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +7 -7
  17. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
  18. package/payload/platform/plugins/anthropic/skills/get-api-key/SKILL.md +2 -2
  19. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +1 -1
  20. package/payload/platform/plugins/docs/references/access-control.md +10 -10
  21. package/payload/platform/plugins/docs/references/contacts-guide.md +11 -11
  22. package/payload/platform/plugins/docs/references/deployment.md +13 -13
  23. package/payload/platform/plugins/docs/references/getting-started.md +19 -19
  24. package/payload/platform/plugins/docs/references/internals.md +4 -4
  25. package/payload/platform/plugins/docs/references/memory-guide.md +21 -21
  26. package/payload/platform/plugins/docs/references/migration-guide.md +5 -5
  27. package/payload/platform/plugins/docs/references/platform.md +9 -9
  28. package/payload/platform/plugins/docs/references/plugins-guide.md +20 -12
  29. package/payload/platform/plugins/docs/references/projects-guide.md +10 -10
  30. package/payload/platform/plugins/docs/references/settings.md +13 -13
  31. package/payload/platform/plugins/docs/references/telegram-guide.md +14 -14
  32. package/payload/platform/plugins/docs/references/troubleshooting.md +23 -23
  33. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +6 -6
  34. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/profile.md +2 -2
  35. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +2 -2
  36. package/payload/platform/plugins/workflows/mcp/test-workflows.sh +5 -1
  37. package/payload/platform/scripts/dedupe-userprofile-ghosts.sh +388 -0
  38. package/payload/platform/scripts/embed-backfill.sh +8 -1
  39. package/payload/platform/scripts/migrate-import.sh +42 -1
  40. package/payload/platform/scripts/seed-neo4j.sh +1 -0
  41. package/payload/server/chunk-PQ6LDXZ4.js +2997 -0
  42. package/payload/server/chunk-W6ZUNLLS.js +9446 -0
  43. package/payload/server/client-pool-DQBHSKAF.js +28 -0
  44. package/payload/server/maxy-edge.js +2 -2
  45. package/payload/server/server.js +41 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.740",
3
+ "version": "1.0.741",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Brand templating — single source of truth for the operator-visible brand name.
3
+ *
4
+ * Skills, agent templates, plugin manifests, and reference content reference
5
+ * the brand only via the literal `{{productName}}` placeholder. This module
6
+ * substitutes at read time from `brand.json`. Same shadow-source defect class
7
+ * as Tasks 787/788: there is no fallback; missing or empty `productName`
8
+ * hard-fails so the wrong brand can never reach the system prompt or the
9
+ * operator UI silently.
10
+ *
11
+ * Used by both `platform/ui` (admin/public agent system-prompt assembly) and
12
+ * `platform/plugins/admin/mcp` (the `plugin-read` MCP tool). Both call sites
13
+ * pass the absolute file path as `sourcePath` so the diagnostic line names
14
+ * exactly which file was substituted.
15
+ */
16
+ export declare function getBrandProductName(): string;
17
+ export declare function substituteBrandPlaceholders(content: string, sourcePath: string): string;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAmBH,wBAAgB,mBAAmB,IAAI,MAAM,CAsB5C;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkBvF"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ /**
3
+ * Brand templating — single source of truth for the operator-visible brand name.
4
+ *
5
+ * Skills, agent templates, plugin manifests, and reference content reference
6
+ * the brand only via the literal `{{productName}}` placeholder. This module
7
+ * substitutes at read time from `brand.json`. Same shadow-source defect class
8
+ * as Tasks 787/788: there is no fallback; missing or empty `productName`
9
+ * hard-fails so the wrong brand can never reach the system prompt or the
10
+ * operator UI silently.
11
+ *
12
+ * Used by both `platform/ui` (admin/public agent system-prompt assembly) and
13
+ * `platform/plugins/admin/mcp` (the `plugin-read` MCP tool). Both call sites
14
+ * pass the absolute file path as `sourcePath` so the diagnostic line names
15
+ * exactly which file was substituted.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.getBrandProductName = getBrandProductName;
19
+ exports.substituteBrandPlaceholders = substituteBrandPlaceholders;
20
+ const node_path_1 = require("node:path");
21
+ const node_fs_1 = require("node:fs");
22
+ const PLACEHOLDER = "{{productName}}";
23
+ let cachedProductName = null;
24
+ function brandJsonPath() {
25
+ const platformRoot = process.env.MAXY_PLATFORM_ROOT;
26
+ if (!platformRoot) {
27
+ throw new Error("[skill-loader] MAXY_PLATFORM_ROOT not set — cannot resolve brand.json");
28
+ }
29
+ return (0, node_path_1.join)(platformRoot, "config", "brand.json");
30
+ }
31
+ function getBrandProductName() {
32
+ if (cachedProductName !== null)
33
+ return cachedProductName;
34
+ const path = brandJsonPath();
35
+ if (!(0, node_fs_1.existsSync)(path)) {
36
+ throw new Error(`[skill-loader] brand.json missing at ${path}`);
37
+ }
38
+ let parsed;
39
+ try {
40
+ parsed = JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
41
+ }
42
+ catch (err) {
43
+ throw new Error(`[skill-loader] brand.json unreadable at ${path}: ${err instanceof Error ? err.message : String(err)}`);
44
+ }
45
+ const value = parsed.productName;
46
+ if (typeof value !== "string" || value.trim() === "") {
47
+ throw new Error(`[skill-loader] brand.json at ${path} has missing or empty productName`);
48
+ }
49
+ cachedProductName = value;
50
+ return value;
51
+ }
52
+ function substituteBrandPlaceholders(content, sourcePath) {
53
+ if (!content.includes(PLACEHOLDER))
54
+ return content;
55
+ let productName;
56
+ try {
57
+ productName = getBrandProductName();
58
+ }
59
+ catch (err) {
60
+ console.error(`[skill-loader] ERROR: brand.json missing — cannot resolve productName for skill ${sourcePath}`);
61
+ throw err;
62
+ }
63
+ // split-length counts non-overlapping literal matches without regex-escape risk.
64
+ const occurrences = content.split(PLACEHOLDER).length - 1;
65
+ const substituted = content.split(PLACEHOLDER).join(productName);
66
+ console.log(`[skill-loader] brand-substituted productName=${productName} skill=${sourcePath} occurrences=${occurrences}`);
67
+ return substituted;
68
+ }
69
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AAmBH,kDAsBC;AAED,kEAkBC;AA3DD,yCAAiC;AACjC,qCAAmD;AAEnD,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAEtC,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAE5C,SAAS,aAAa;IACpB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACpD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,IAAA,gBAAI,EAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AACpD,CAAC;AAED,SAAgB,mBAAmB;IACjC,IAAI,iBAAiB,KAAK,IAAI;QAAE,OAAO,iBAAiB,CAAC;IACzD,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,IAAA,oBAAU,EAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,MAAiC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,2CAA2C,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACvG,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,mCAAmC,CACxE,CAAC;IACJ,CAAC;IACD,iBAAiB,GAAG,KAAK,CAAC;IAC1B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,2BAA2B,CAAC,OAAe,EAAE,UAAkB;IAC7E,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,OAAO,CAAC;IACnD,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,WAAW,GAAG,mBAAmB,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,mFAAmF,UAAU,EAAE,CAChG,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,iFAAiF;IACjF,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CACT,gDAAgD,WAAW,UAAU,UAAU,gBAAgB,WAAW,EAAE,CAC7G,CAAC;IACF,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Brand templating — single source of truth for the operator-visible brand name.
3
+ *
4
+ * Skills, agent templates, plugin manifests, and reference content reference
5
+ * the brand only via the literal `{{productName}}` placeholder. This module
6
+ * substitutes at read time from `brand.json`. Same shadow-source defect class
7
+ * as Tasks 787/788: there is no fallback; missing or empty `productName`
8
+ * hard-fails so the wrong brand can never reach the system prompt or the
9
+ * operator UI silently.
10
+ *
11
+ * Used by both `platform/ui` (admin/public agent system-prompt assembly) and
12
+ * `platform/plugins/admin/mcp` (the `plugin-read` MCP tool). Both call sites
13
+ * pass the absolute file path as `sourcePath` so the diagnostic line names
14
+ * exactly which file was substituted.
15
+ */
16
+
17
+ import { join } from "node:path";
18
+ import { existsSync, readFileSync } from "node:fs";
19
+
20
+ const PLACEHOLDER = "{{productName}}";
21
+
22
+ let cachedProductName: string | null = null;
23
+
24
+ function brandJsonPath(): string {
25
+ const platformRoot = process.env.MAXY_PLATFORM_ROOT;
26
+ if (!platformRoot) {
27
+ throw new Error(
28
+ "[skill-loader] MAXY_PLATFORM_ROOT not set — cannot resolve brand.json",
29
+ );
30
+ }
31
+ return join(platformRoot, "config", "brand.json");
32
+ }
33
+
34
+ export function getBrandProductName(): string {
35
+ if (cachedProductName !== null) return cachedProductName;
36
+ const path = brandJsonPath();
37
+ if (!existsSync(path)) {
38
+ throw new Error(`[skill-loader] brand.json missing at ${path}`);
39
+ }
40
+ let parsed: { productName?: unknown };
41
+ try {
42
+ parsed = JSON.parse(readFileSync(path, "utf-8"));
43
+ } catch (err) {
44
+ throw new Error(
45
+ `[skill-loader] brand.json unreadable at ${path}: ${err instanceof Error ? err.message : String(err)}`,
46
+ );
47
+ }
48
+ const value = parsed.productName;
49
+ if (typeof value !== "string" || value.trim() === "") {
50
+ throw new Error(
51
+ `[skill-loader] brand.json at ${path} has missing or empty productName`,
52
+ );
53
+ }
54
+ cachedProductName = value;
55
+ return value;
56
+ }
57
+
58
+ export function substituteBrandPlaceholders(content: string, sourcePath: string): string {
59
+ if (!content.includes(PLACEHOLDER)) return content;
60
+ let productName: string;
61
+ try {
62
+ productName = getBrandProductName();
63
+ } catch (err) {
64
+ console.error(
65
+ `[skill-loader] ERROR: brand.json missing — cannot resolve productName for skill ${sourcePath}`,
66
+ );
67
+ throw err;
68
+ }
69
+ // split-length counts non-overlapping literal matches without regex-escape risk.
70
+ const occurrences = content.split(PLACEHOLDER).length - 1;
71
+ const substituted = content.split(PLACEHOLDER).join(productName);
72
+ console.log(
73
+ `[skill-loader] brand-substituted productName=${productName} skill=${sourcePath} occurrences=${occurrences}`,
74
+ );
75
+ return substituted;
76
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,4EAA4E;IAC5E,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,SAAS,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAuF1B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,4EAA4E;IAC5E,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,SAAS,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,CA8G1B"}
@@ -59,7 +59,29 @@ async function writeNodeWithEdges(params) {
59
59
  process.stderr.write(`[graph-write] reject reason=unresolved-target labels=${labelCsv} agent=${agentLabel} requested=${uniqueRequested} found=${found}\n`);
60
60
  throw new Error(`Write doctrine violated: ${uniqueRequested - found} of ${uniqueRequested} relationship target(s) did not resolve (elementId mismatch). No node created.`);
61
61
  }
62
- const nodeRes = await tx.run(`CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`, { props: nodeProps });
62
+ let nodeRes;
63
+ try {
64
+ nodeRes = await tx.run(`CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`, { props: nodeProps });
65
+ }
66
+ catch (err) {
67
+ // Task 792: surface UserProfile uniqueness violations as a structured
68
+ // reject line. Neo4j's ConstraintValidationFailed message names the
69
+ // violated label + properties (e.g. "Node(N) already exists with label
70
+ // `UserProfile` and properties accountId=… userId=…") but NOT the
71
+ // constraint name, so we key on the helper's input `labels` parameter
72
+ // rather than parsing the message. Other constraint violations
73
+ // propagate without specialised logging — they are unexpected and the
74
+ // raw error is the right signal.
75
+ const code = err?.code ?? "";
76
+ if (code === "Neo.ClientError.Schema.ConstraintValidationFailed" && labels.includes("UserProfile")) {
77
+ const accountIdProp = nodeProps.accountId;
78
+ const userIdProp = nodeProps.userId;
79
+ const acctSlice = typeof accountIdProp === "string" ? accountIdProp.slice(0, 8) : "unknown";
80
+ const userSlice = typeof userIdProp === "string" ? userIdProp.slice(0, 8) : "unknown";
81
+ process.stderr.write(`[graph-write] reject reason=user-profile-uniqueness-violation accountId=${acctSlice} userId=${userSlice} writer=${agentLabel}\n`);
82
+ }
83
+ throw err;
84
+ }
63
85
  const nodeId = nodeRes.records[0].get("nodeId");
64
86
  const nodeLabels = nodeRes.records[0].get("nodeLabels");
65
87
  // Neo4j Community's default isolation is read-committed (not snapshot)
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -112,10 +112,33 @@ export async function writeNodeWithEdges(
112
112
  );
113
113
  }
114
114
 
115
- const nodeRes = await tx.run(
116
- `CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`,
117
- { props: nodeProps }
118
- );
115
+ let nodeRes;
116
+ try {
117
+ nodeRes = await tx.run(
118
+ `CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`,
119
+ { props: nodeProps }
120
+ );
121
+ } catch (err) {
122
+ // Task 792: surface UserProfile uniqueness violations as a structured
123
+ // reject line. Neo4j's ConstraintValidationFailed message names the
124
+ // violated label + properties (e.g. "Node(N) already exists with label
125
+ // `UserProfile` and properties accountId=… userId=…") but NOT the
126
+ // constraint name, so we key on the helper's input `labels` parameter
127
+ // rather than parsing the message. Other constraint violations
128
+ // propagate without specialised logging — they are unexpected and the
129
+ // raw error is the right signal.
130
+ const code = (err as { code?: string } | null)?.code ?? "";
131
+ if (code === "Neo.ClientError.Schema.ConstraintValidationFailed" && labels.includes("UserProfile")) {
132
+ const accountIdProp = (nodeProps as Record<string, unknown>).accountId;
133
+ const userIdProp = (nodeProps as Record<string, unknown>).userId;
134
+ const acctSlice = typeof accountIdProp === "string" ? accountIdProp.slice(0, 8) : "unknown";
135
+ const userSlice = typeof userIdProp === "string" ? userIdProp.slice(0, 8) : "unknown";
136
+ process.stderr.write(
137
+ `[graph-write] reject reason=user-profile-uniqueness-violation accountId=${acctSlice} userId=${userSlice} writer=${agentLabel}\n`
138
+ );
139
+ }
140
+ throw err;
141
+ }
119
142
  const nodeId = nodeRes.records[0].get("nodeId") as string;
120
143
  const nodeLabels = nodeRes.records[0].get("nodeLabels") as string[];
121
144
 
@@ -577,8 +577,11 @@ FOR (sr:StepResult) ON (sr.runId);
577
577
  // ----------------------------------------------------------
578
578
 
579
579
  // Composite unique constraint: one profile per admin per account.
580
- // Replaces the single-key accountId constraint (Task 249).
581
- CREATE CONSTRAINT user_profile_account_user_unique IF NOT EXISTS
580
+ // Replaces the single-key accountId constraint (Task 249) and the
581
+ // transitional name `user_profile_account_user_unique` (Task 792 — renamed
582
+ // for grep parity with the doctrine name in .docs/neo4j.md and the
583
+ // per-bucket dedupe script). Old name dropped in seed-neo4j.sh MIGRATE_EOF.
584
+ CREATE CONSTRAINT user_profile_unique_per_user IF NOT EXISTS
582
585
  FOR (up:UserProfile) REQUIRE (up.accountId, up.userId) IS UNIQUE;
583
586
 
584
587
  // ----------------------------------------------------------
@@ -6,8 +6,8 @@
6
6
  "plugins/*/mcp"
7
7
  ],
8
8
  "scripts": {
9
- "build": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
10
- "build:lib": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json",
9
+ "build": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
10
+ "build:lib": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json",
11
11
  "build:memory": "tsc -p plugins/memory/mcp/tsconfig.json",
12
12
  "build:contacts": "tsc -p plugins/contacts/mcp/tsconfig.json",
13
13
  "build:telegram": "tsc -p plugins/telegram/mcp/tsconfig.json",
@@ -9,6 +9,7 @@ import { execFileSync } from "node:child_process";
9
9
  import { appendFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
10
10
  import { writeKey, validateKey, hasKey, keyFilePath, deleteKey } from "../../../../lib/anthropic-key/dist/index.js";
11
11
  import { deviceUrlBlock } from "../../../../lib/device-url/dist/index.js";
12
+ import { substituteBrandPlaceholders } from "../../../../lib/brand-templating/dist/index.js";
12
13
  import { createHash, randomInt, randomUUID } from "node:crypto";
13
14
  import { createConnection } from "node:net";
14
15
  import { homedir, hostname as osHostname } from "node:os";
@@ -1226,7 +1227,11 @@ server.tool("plugin-read", "Read a plugin definition (PLUGIN.md) or one of its r
1226
1227
  isError: true,
1227
1228
  };
1228
1229
  }
1229
- const content = await readFile(pluginPath, "utf-8");
1230
+ const rawContent = await readFile(pluginPath, "utf-8");
1231
+ // Brand-substitute every plugin file before it reaches the agent —
1232
+ // PLUGIN.md, skills/<name>/SKILL.md, references/*.md all flow through
1233
+ // here. Missing brand.json hard-throws (Tasks 787/788 doctrine).
1234
+ const content = substituteBrandPlaceholders(rawContent, pluginPath);
1230
1235
  // Append file inventory on default calls (PLUGIN.md) so agents can discover
1231
1236
  // skill and reference paths without guessing
1232
1237
  if (resolvedFile === "PLUGIN.md") {