@fleox-agent-crm/agentcrm 0.0.0-stage → 0.3.1

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 (129) hide show
  1. package/LICENSE +143 -0
  2. package/README.md +223 -2
  3. package/changelog.json +76 -0
  4. package/dist/admin/admin-files.json +26 -0
  5. package/dist/admin/assets/chartsImpl-B45AAqnr.js +91 -0
  6. package/dist/admin/assets/firebase-C1x_l9P9.js +2 -0
  7. package/dist/admin/assets/gitJson-CAUSxl8d.js +3 -0
  8. package/dist/admin/assets/index-ChFauO8y.js +1181 -0
  9. package/dist/admin/assets/index-TcjySLVg.css +1 -0
  10. package/dist/admin/assets/index.esm-BFc7vwnl.js +400 -0
  11. package/dist/admin/assets/index.esm-CtEQZRb1.js +1651 -0
  12. package/dist/admin/assets/index.esm-Dum0J07z.js +16 -0
  13. package/dist/admin/assets/index.esm2017-EOzKbpUS.js +390 -0
  14. package/dist/admin/assets/lucide-react.min--rznIkmQ.js +6 -0
  15. package/dist/admin/assets/sdk-DgzLACmL.js +1717 -0
  16. package/dist/admin/config.js +3 -0
  17. package/dist/admin/favicon.svg +1 -0
  18. package/dist/admin/index.html +139 -0
  19. package/dist/admin/runtime/agentcrm-runtime.js +104 -0
  20. package/dist/admin/runtime/lucide-react.js +791 -0
  21. package/dist/admin/runtime/react-dom-client.js +17 -0
  22. package/dist/admin/runtime/react-dom.js +20 -0
  23. package/dist/admin/runtime/react-i18next.js +19 -0
  24. package/dist/admin/runtime/react-jsx-runtime.js +17 -0
  25. package/dist/admin/runtime/react.js +22 -0
  26. package/dist/agent/agentcrm.mjs +4057 -0
  27. package/dist/agent/chunks/_commonjsHelpers-ClciMIcB.mjs +14 -0
  28. package/dist/agent/chunks/activities-Cj_SIOay.mjs +227 -0
  29. package/dist/agent/chunks/api-Cz0Ubj-B.mjs +98 -0
  30. package/dist/agent/chunks/appearance-BloHbiLA.mjs +174 -0
  31. package/dist/agent/chunks/automations-DwWruxmu.mjs +698 -0
  32. package/dist/agent/chunks/backup-W3CjgkAJ.mjs +116 -0
  33. package/dist/agent/chunks/batch-CVETiJj5.mjs +142 -0
  34. package/dist/agent/chunks/compact-BGHI92tm.mjs +69 -0
  35. package/dist/agent/chunks/context-CxFfqS4D.mjs +65 -0
  36. package/dist/agent/chunks/core-Dy7vY9H6.mjs +255 -0
  37. package/dist/agent/chunks/dedupe-BepmsaHv.mjs +123 -0
  38. package/dist/agent/chunks/encoding-C9MzdP95.mjs +36 -0
  39. package/dist/agent/chunks/exportCsv-C6e6XEmB.mjs +130 -0
  40. package/dist/agent/chunks/extCheck-GgHG1dYB.mjs +200 -0
  41. package/dist/agent/chunks/extPackage-DuZ6GZhp.mjs +115 -0
  42. package/dist/agent/chunks/extScaffold-Aqyjf1nr.mjs +320 -0
  43. package/dist/agent/chunks/extensionActions-D2HtpQz4.mjs +48 -0
  44. package/dist/agent/chunks/extensions-Bp72uZ9a.mjs +164 -0
  45. package/dist/agent/chunks/featureRegistry-DSsZbhrh.mjs +149 -0
  46. package/dist/agent/chunks/fields-B0bitgmr.mjs +476 -0
  47. package/dist/agent/chunks/files-CjsPJSR6.mjs +158 -0
  48. package/dist/agent/chunks/files-D1daDgY0.mjs +367 -0
  49. package/dist/agent/chunks/firebase-DxGVQV9E.mjs +454 -0
  50. package/dist/agent/chunks/firebaseRules-iori-s7U.mjs +221 -0
  51. package/dist/agent/chunks/forms-BfuWaQjA.mjs +847 -0
  52. package/dist/agent/chunks/gitJson-fjr8mcHe.mjs +528 -0
  53. package/dist/agent/chunks/hosting-Bme7LxPc.mjs +144 -0
  54. package/dist/agent/chunks/http-Bk9ICb7I.mjs +127 -0
  55. package/dist/agent/chunks/ids-CvnmrMJX.mjs +59 -0
  56. package/dist/agent/chunks/ids-u-noYcy5.mjs +14 -0
  57. package/dist/agent/chunks/importCsv-LVmMTaWU.mjs +334 -0
  58. package/dist/agent/chunks/index-B-4W0-P4.mjs +535 -0
  59. package/dist/agent/chunks/index-BM8qeGOb.mjs +2489 -0
  60. package/dist/agent/chunks/index-Bnmav-Oh.mjs +311 -0
  61. package/dist/agent/chunks/index-CRkw3_iF.mjs +147 -0
  62. package/dist/agent/chunks/index-CWrrF1wl.mjs +111 -0
  63. package/dist/agent/chunks/index-DUSdTBkz.mjs +2988 -0
  64. package/dist/agent/chunks/index-RCmo-uld.mjs +26 -0
  65. package/dist/agent/chunks/index-w03ReRs4.mjs +9780 -0
  66. package/dist/agent/chunks/install-CbpD_7gd.mjs +188 -0
  67. package/dist/agent/chunks/jsx-runtime-Ca2uwGDr.mjs +76 -0
  68. package/dist/agent/chunks/loader-MPD9iAvh.mjs +184 -0
  69. package/dist/agent/chunks/lucide-react.min-Bt3gtepY.mjs +64 -0
  70. package/dist/agent/chunks/memory-WNR3VHUJ.mjs +56 -0
  71. package/dist/agent/chunks/migrate-CsClnnN8.mjs +182 -0
  72. package/dist/agent/chunks/modules-clWdE-K2.mjs +202 -0
  73. package/dist/agent/chunks/nodeImport-ylfRDvqt.mjs +38 -0
  74. package/dist/agent/chunks/package-B7mI6HGi.mjs +194 -0
  75. package/dist/agent/chunks/papaparse-Df7i1dHr.mjs +1309 -0
  76. package/dist/agent/chunks/pipelines-BAKpPk1w.mjs +234 -0
  77. package/dist/agent/chunks/plan-BmTat6-T.mjs +254 -0
  78. package/dist/agent/chunks/pluginRegistry-DyHtlkcr.mjs +83 -0
  79. package/dist/agent/chunks/query-C5nJB_3C.mjs +192 -0
  80. package/dist/agent/chunks/records-DcHFelq5.mjs +2195 -0
  81. package/dist/agent/chunks/registry-COfJrSmg.mjs +182 -0
  82. package/dist/agent/chunks/registry-DijAKZ24.mjs +431 -0
  83. package/dist/agent/chunks/relations-B9TynBmA.mjs +191 -0
  84. package/dist/agent/chunks/reports-BACHGccj.mjs +189 -0
  85. package/dist/agent/chunks/runtime-C0Xf0Axi.mjs +14873 -0
  86. package/dist/agent/chunks/runtimeConfig-CCOFg1RM.mjs +250 -0
  87. package/dist/agent/chunks/s3-Dz50-NuA.mjs +903 -0
  88. package/dist/agent/chunks/schema-C4lSslXv.mjs +373 -0
  89. package/dist/agent/chunks/schema-DnLj8dUO.mjs +213 -0
  90. package/dist/agent/chunks/sdk-whvfg786.mjs +43644 -0
  91. package/dist/agent/chunks/seed-6MRmQQBR.mjs +541 -0
  92. package/dist/agent/chunks/server-DC3t8r30.mjs +242 -0
  93. package/dist/agent/chunks/settings-Di8nzNEL.mjs +111 -0
  94. package/dist/agent/chunks/standardObjects-CheqfDqa.mjs +243 -0
  95. package/dist/agent/chunks/stats-BfuLWhVV.mjs +51 -0
  96. package/dist/agent/chunks/store-5gqRSKXg.mjs +122 -0
  97. package/dist/agent/chunks/themes-DPZFv3yc.mjs +43 -0
  98. package/dist/agent/chunks/tools-iSH-yMpl.mjs +884 -0
  99. package/dist/agent/chunks/types-BOy9PUl7.mjs +44 -0
  100. package/dist/agent/chunks/users-DI1BvS0f.mjs +107 -0
  101. package/dist/agent/chunks/utils-DmI8FtXP.mjs +83 -0
  102. package/dist/agent/chunks/views-DH1n9Lrt.mjs +109 -0
  103. package/dist/version.json +7 -0
  104. package/package.json +97 -4
  105. package/plugin/.claude-plugin/plugin.json +17 -0
  106. package/plugin/skills/agentcrm-admin/SKILL.md +191 -0
  107. package/plugin/skills/agentcrm-admin/references/appearance.md +26 -0
  108. package/plugin/skills/agentcrm-admin/references/import.md +16 -0
  109. package/plugin/skills/agentcrm-admin/references/records.md +30 -0
  110. package/plugin/skills/agentcrm-admin/references/schema.md +59 -0
  111. package/plugin/skills/agentcrm-extensions/SKILL.md +93 -0
  112. package/plugin/skills/agentcrm-extensions/references/module-recipes.md +213 -0
  113. package/plugin/skills/agentcrm-extensions/references/runtime-api.md +41 -0
  114. package/plugin/skills/agentcrm-extensions/references/testing.md +78 -0
  115. package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +65 -0
  116. package/plugin/skills/agentcrm-install/SKILL.md +116 -0
  117. package/plugin/skills/agentcrm-install/references/firebase.md +18 -0
  118. package/plugin/skills/agentcrm-install/references/github.md +20 -0
  119. package/plugin/skills/agentcrm-install/references/mcp.md +17 -0
  120. package/plugin/skills/agentcrm-install/references/plans.md +45 -0
  121. package/plugin/skills/agentcrm-install/references/s3.md +24 -0
  122. package/plugin/skills/agentcrm-manage/SKILL.md +108 -0
  123. package/plugin/skills/agentcrm-manage/references/cron.md +11 -0
  124. package/plugin/skills/agentcrm-manage/references/doctor.md +18 -0
  125. package/plugin/skills/agentcrm-sales/SKILL.md +92 -0
  126. package/plugin/skills/agentcrm-sales/references/enrichment.md +13 -0
  127. package/plugin/skills/agentcrm-sales/references/playbooks.md +29 -0
  128. package/plugin/skills/agentcrm-sales/references/weekly-report.md +27 -0
  129. package/types/agentcrm-runtime.d.ts +894 -0
@@ -0,0 +1,44 @@
1
+ import { createRequire as __acrmRequire } from "node:module";
2
+ import { fileURLToPath as __acrmPath } from "node:url";
3
+ import { dirname as __acrmDirname } from "node:path";
4
+ const require2 = __acrmRequire(import.meta.url);
5
+ const __filename = __acrmPath(import.meta.url);
6
+ const __dirname = __acrmDirname(__filename);
7
+ const COLLECTIONS = [
8
+ "objects",
9
+ "records",
10
+ "activities",
11
+ "pipelines",
12
+ "views",
13
+ "automations",
14
+ "forms",
15
+ "users",
16
+ "settings",
17
+ "config",
18
+ "automationRuns",
19
+ "extensions",
20
+ "files"
21
+ ];
22
+ function isCollectionName(value) {
23
+ return typeof value === "string" && COLLECTIONS.includes(value);
24
+ }
25
+ class DocConflictError extends Error {
26
+ constructor(message, collection, id) {
27
+ super(message);
28
+ this.collection = collection;
29
+ this.id = id;
30
+ this.name = "DocConflictError";
31
+ }
32
+ }
33
+ class StoreNotReadyError extends Error {
34
+ constructor(message = "The data store is not ready.") {
35
+ super(message);
36
+ this.name = "StoreNotReadyError";
37
+ }
38
+ }
39
+ export {
40
+ COLLECTIONS,
41
+ DocConflictError,
42
+ StoreNotReadyError,
43
+ isCollectionName
44
+ };
@@ -0,0 +1,107 @@
1
+ import { createRequire as __acrmRequire } from "node:module";
2
+ import { fileURLToPath as __acrmPath } from "node:url";
3
+ import { dirname as __acrmDirname } from "node:path";
4
+ const require2 = __acrmRequire(import.meta.url);
5
+ const __filename = __acrmPath(import.meta.url);
6
+ const __dirname = __acrmDirname(__filename);
7
+ import { n as newId } from "./ids-CvnmrMJX.mjs";
8
+ import { U as USER_ROLES } from "../agentcrm.mjs";
9
+ import { normalizeEmail } from "./fields-B0bitgmr.mjs";
10
+ import { assertCan, OpsError } from "./context-CxFfqS4D.mjs";
11
+ import { userOf, asDoc, usersOf } from "./store-5gqRSKXg.mjs";
12
+ import "node:util";
13
+ import "node:fs";
14
+ import "node:path";
15
+ import "node:url";
16
+ import "node:crypto";
17
+ import "node:os";
18
+ import "node:child_process";
19
+ import "node:http";
20
+ import "./pluginRegistry-DyHtlkcr.mjs";
21
+ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
22
+ function listUsers(ctx, opts = {}) {
23
+ assertCan(ctx, "users.read");
24
+ return usersOf(ctx.store).filter((u) => opts.includeDisabled !== false || !u.disabled).sort((a, b) => a.name.localeCompare(b.name));
25
+ }
26
+ function getUser(ctx, id) {
27
+ assertCan(ctx, "users.read");
28
+ const u = userOf(ctx.store, id);
29
+ if (!u) throw new OpsError("notFound", `User "${id}" not found.`);
30
+ return u;
31
+ }
32
+ function findUserByEmail(ctx, email) {
33
+ const e = normalizeEmail(email);
34
+ return usersOf(ctx.store).find((u) => normalizeEmail(u.email) === e);
35
+ }
36
+ function activeAdmins(ctx) {
37
+ return usersOf(ctx.store).filter((u) => u.role === "admin" && !u.disabled);
38
+ }
39
+ async function createUser(ctx, input) {
40
+ assertCan(ctx, "users.write");
41
+ const email = normalizeEmail(input.email);
42
+ if (!EMAIL_RE.test(email)) throw new OpsError("validation", `"${input.email}" is not a valid email address.`);
43
+ if (findUserByEmail(ctx, email)) throw new OpsError("conflict", `A user with email ${email} already exists.`);
44
+ const role = input.role ?? "member";
45
+ if (!USER_ROLES.includes(role)) throw new OpsError("validation", `Unknown role "${role}".`);
46
+ const id = input.id ?? newId(ctx.now());
47
+ if (userOf(ctx.store, id)) throw new OpsError("conflict", `User "${id}" already exists.`);
48
+ const user = { id, email, name: input.name?.trim() || email.split("@")[0], role, ...input.avatarUrl ? { avatarUrl: input.avatarUrl } : {} };
49
+ await ctx.store.write([{ op: "set", collection: "users", doc: asDoc(user) }], { message: `Add user ${email}` });
50
+ return getUser(ctx, id);
51
+ }
52
+ async function updateUser(ctx, id, patch) {
53
+ const before = getUser(ctx, id);
54
+ const self = ctx.user?.id === id;
55
+ const adminOnly = patch.role !== void 0 || patch.disabled !== void 0 || patch.email !== void 0;
56
+ if (!self || adminOnly) assertCan(ctx, "users.write");
57
+ const fields = {};
58
+ if (patch.name !== void 0) fields.name = patch.name.trim() || before.name;
59
+ if (patch.avatarUrl !== void 0) fields.avatarUrl = patch.avatarUrl || void 0;
60
+ if (patch.email !== void 0) {
61
+ const email = normalizeEmail(patch.email);
62
+ if (!EMAIL_RE.test(email)) throw new OpsError("validation", `"${patch.email}" is not a valid email address.`);
63
+ const other = findUserByEmail(ctx, email);
64
+ if (other && other.id !== id) throw new OpsError("conflict", `A user with email ${email} already exists.`);
65
+ fields.email = email;
66
+ }
67
+ if (patch.role !== void 0) {
68
+ if (!USER_ROLES.includes(patch.role)) throw new OpsError("validation", `Unknown role "${patch.role}".`);
69
+ fields.role = patch.role;
70
+ }
71
+ if (patch.disabled !== void 0) fields.disabled = patch.disabled || void 0;
72
+ const losesAdmin = before.role === "admin" && !before.disabled && (fields.role && fields.role !== "admin" || fields.disabled);
73
+ if (losesAdmin && activeAdmins(ctx).length <= 1) throw new OpsError("invalid", "The CRM needs at least one active admin.");
74
+ await ctx.store.write([{ op: "patch", collection: "users", id, fields }], { message: `Update user ${before.email}` });
75
+ return getUser(ctx, id);
76
+ }
77
+ function setUserRole(ctx, id, role) {
78
+ return updateUser(ctx, id, { role });
79
+ }
80
+ async function deleteUser(ctx, id, opts = {}) {
81
+ assertCan(ctx, "users.write");
82
+ const user = getUser(ctx, id);
83
+ if (user.role === "admin" && !user.disabled && activeAdmins(ctx).length <= 1) throw new OpsError("invalid", "The CRM needs at least one active admin.");
84
+ if (opts.reassignTo) getUser(ctx, opts.reassignTo);
85
+ const mutations = [{ op: "delete", collection: "users", id }];
86
+ let reassigned = 0;
87
+ for (const r of ctx.store.list("records")) {
88
+ if (r.ownerId === id) {
89
+ reassigned++;
90
+ mutations.push({ op: "patch", collection: "records", id: r.id, fields: { ownerId: opts.reassignTo } });
91
+ }
92
+ }
93
+ for (const a of ctx.store.list("activities")) {
94
+ if (a.assigneeId === id) mutations.push({ op: "patch", collection: "activities", id: a.id, fields: { assigneeId: opts.reassignTo } });
95
+ }
96
+ await ctx.store.write(mutations, { message: `Remove user ${user.email}` });
97
+ return { id, reassigned };
98
+ }
99
+ export {
100
+ createUser,
101
+ deleteUser,
102
+ findUserByEmail,
103
+ getUser,
104
+ listUsers,
105
+ setUserRole,
106
+ updateUser
107
+ };
@@ -0,0 +1,83 @@
1
+ import { createRequire as __acrmRequire } from "node:module";
2
+ import { fileURLToPath as __acrmPath } from "node:url";
3
+ import { dirname as __acrmDirname } from "node:path";
4
+ const require2 = __acrmRequire(import.meta.url);
5
+ const __filename = __acrmPath(import.meta.url);
6
+ const __dirname = __acrmDirname(__filename);
7
+ function r(e) {
8
+ var t, f, n = "";
9
+ if ("string" == typeof e || "number" == typeof e) n += e;
10
+ else if ("object" == typeof e) if (Array.isArray(e)) {
11
+ var o = e.length;
12
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
13
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
14
+ return n;
15
+ }
16
+ function clsx() {
17
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
18
+ return n;
19
+ }
20
+ const cn = (...args) => clsx(...args);
21
+ function toDate(value) {
22
+ if (value == null || value === "") return null;
23
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
24
+ const date = new Date(value);
25
+ return Number.isNaN(date.getTime()) ? null : date;
26
+ }
27
+ function formatDate(value, locale = "en") {
28
+ const date = toDate(value);
29
+ if (!date) return "—";
30
+ return new Intl.DateTimeFormat(locale, { month: "short", day: "numeric", year: "numeric" }).format(date);
31
+ }
32
+ function formatDateTime(value, locale = "en") {
33
+ const date = toDate(value);
34
+ if (!date) return "—";
35
+ return new Intl.DateTimeFormat(locale, {
36
+ month: "short",
37
+ day: "numeric",
38
+ year: "numeric",
39
+ hour: "2-digit",
40
+ minute: "2-digit"
41
+ }).format(date);
42
+ }
43
+ function formatRelative(value, locale = "en", now = Date.now()) {
44
+ const date = toDate(value);
45
+ if (!date) return "—";
46
+ const diff = date.getTime() - now;
47
+ const abs = Math.abs(diff);
48
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
49
+ const units = [
50
+ ["year", 365 * 864e5],
51
+ ["month", 30 * 864e5],
52
+ ["week", 7 * 864e5],
53
+ ["day", 864e5],
54
+ ["hour", 36e5],
55
+ ["minute", 6e4]
56
+ ];
57
+ for (const [unit, ms] of units) {
58
+ if (abs >= ms) return rtf.format(Math.round(diff / ms), unit);
59
+ }
60
+ return rtf.format(0, "minute");
61
+ }
62
+ function slugify(input) {
63
+ return input.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
64
+ }
65
+ function camelId(input) {
66
+ const parts = slugify(input).split("-").filter(Boolean);
67
+ if (parts.length === 0) return "";
68
+ const id = parts[0] + parts.slice(1).map((p) => p[0].toUpperCase() + p.slice(1)).join("");
69
+ return /^[0-9]/.test(id) ? `f${id}` : id;
70
+ }
71
+ function initials(name) {
72
+ const parts = (name ?? "").trim().split(/\s+/).filter(Boolean);
73
+ if (parts.length === 0) return "?";
74
+ return ((parts[0][0] ?? "") + (parts.length > 1 ? parts[parts.length - 1][0] : "")).toUpperCase();
75
+ }
76
+ export {
77
+ cn as a,
78
+ formatDateTime as b,
79
+ camelId as c,
80
+ formatDate as d,
81
+ formatRelative as f,
82
+ initials as i
83
+ };
@@ -0,0 +1,109 @@
1
+ import { createRequire as __acrmRequire } from "node:module";
2
+ import { fileURLToPath as __acrmPath } from "node:url";
3
+ import { dirname as __acrmDirname } from "node:path";
4
+ const require2 = __acrmRequire(import.meta.url);
5
+ const __filename = __acrmPath(import.meta.url);
6
+ const __dirname = __acrmDirname(__filename);
7
+ import { n as newId } from "./ids-CvnmrMJX.mjs";
8
+ import { F as FILTER_OPS } from "../agentcrm.mjs";
9
+ import { OpsError, assertCan, can } from "./context-CxFfqS4D.mjs";
10
+ import { listRecords } from "./records-DcHFelq5.mjs";
11
+ import { requireObject, asDoc, viewsOf, thaw, pipelinesOf } from "./store-5gqRSKXg.mjs";
12
+ import "node:util";
13
+ import "node:fs";
14
+ import "node:path";
15
+ import "node:url";
16
+ import "node:crypto";
17
+ import "node:os";
18
+ import "node:child_process";
19
+ import "node:http";
20
+ import "./pluginRegistry-DyHtlkcr.mjs";
21
+ import "./fields-B0bitgmr.mjs";
22
+ import "./query-C5nJB_3C.mjs";
23
+ import "./standardObjects-CheqfDqa.mjs";
24
+ import "./relations-B9TynBmA.mjs";
25
+ function listViews(ctx, objectId) {
26
+ assertCan(ctx, "views.read");
27
+ const uid = ctx.user?.id;
28
+ return viewsOf(ctx.store, objectId).filter((v) => v.shared || !v.ownerId || v.ownerId === uid || ctx.user === null);
29
+ }
30
+ function getView(ctx, id) {
31
+ assertCan(ctx, "views.read");
32
+ const v = ctx.store.get("views", id);
33
+ if (!v) throw new OpsError("notFound", `View "${id}" not found.`);
34
+ return v;
35
+ }
36
+ function assertCanWrite(ctx, view) {
37
+ if (view.shared) return assertCan(ctx, "views.writeShared");
38
+ assertCan(ctx, "views.writeOwn");
39
+ if (ctx.user && view.ownerId && view.ownerId !== ctx.user.id && !can(ctx.user, "views.writeShared")) {
40
+ throw new OpsError("forbidden", "This view belongs to another user.");
41
+ }
42
+ }
43
+ function validateView(ctx, v) {
44
+ const object = requireObject(ctx.store, v.object);
45
+ if (!v.name.trim()) throw new OpsError("validation", "A view needs a name.");
46
+ if (v.type !== "table" && v.type !== "kanban") throw new OpsError("validation", `Unknown view type "${v.type}".`);
47
+ for (const f of v.filters) if (!FILTER_OPS.includes(f.op)) throw new OpsError("validation", `Unknown filter operator "${f.op}".`);
48
+ for (const s of v.sorts) if (s.dir !== "asc" && s.dir !== "desc") throw new OpsError("validation", `Sort direction must be asc or desc.`);
49
+ if (v.type === "kanban") {
50
+ const group = object.fields.find((f) => f.id === v.groupBy);
51
+ if (!group || !["select", "user", "boolean"].includes(group.type)) throw new OpsError("validation", "A kanban view groups by a select, user or checkbox field.");
52
+ if (v.pipelineId && !pipelinesOf(ctx.store, v.object).some((p) => p.id === v.pipelineId)) throw new OpsError("validation", `Unknown pipeline "${v.pipelineId}".`);
53
+ }
54
+ }
55
+ async function createView(ctx, input) {
56
+ const object = requireObject(ctx.store, input.object);
57
+ const view = {
58
+ id: newId(ctx.now()),
59
+ object: object.id,
60
+ name: input.name?.trim() ?? "",
61
+ type: input.type ?? "table",
62
+ columns: input.columns ?? object.fields.filter((f) => !f.hidden).slice(0, 6).map((f) => f.id),
63
+ filters: input.filters ?? [],
64
+ sorts: input.sorts ?? [],
65
+ ...input.groupBy ? { groupBy: input.groupBy } : {},
66
+ ...input.pipelineId ? { pipelineId: input.pipelineId } : {},
67
+ shared: !!input.shared,
68
+ ...!input.shared && ctx.user ? { ownerId: ctx.user.id } : {}
69
+ };
70
+ assertCanWrite(ctx, view);
71
+ validateView(ctx, view);
72
+ await ctx.store.write([{ op: "set", collection: "views", doc: asDoc(view) }], { message: `Create view ${view.name}` });
73
+ return getView(ctx, view.id);
74
+ }
75
+ async function updateView(ctx, id, patch) {
76
+ const before = getView(ctx, id);
77
+ assertCanWrite(ctx, before);
78
+ const next = { ...thaw(before), ...Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== void 0)) };
79
+ if (patch.shared !== void 0 && patch.shared !== before.shared) assertCan(ctx, "views.writeShared");
80
+ if (next.shared) delete next.ownerId;
81
+ else if (!next.ownerId && ctx.user) next.ownerId = ctx.user.id;
82
+ validateView(ctx, next);
83
+ await ctx.store.write([{ op: "set", collection: "views", doc: asDoc(next) }], { message: `Update view ${next.name}` });
84
+ return getView(ctx, id);
85
+ }
86
+ async function duplicateView(ctx, id, name) {
87
+ const v = getView(ctx, id);
88
+ return createView(ctx, { ...thaw(v), name: name ?? `${v.name} (copy)`, shared: false });
89
+ }
90
+ async function deleteView(ctx, id) {
91
+ const v = getView(ctx, id);
92
+ assertCanWrite(ctx, v);
93
+ if (viewsOf(ctx.store, v.object).length <= 1) throw new OpsError("invalid", "An object keeps at least one view.");
94
+ await ctx.store.write([{ op: "delete", collection: "views", id }], { message: `Delete view ${v.name}` });
95
+ return { id };
96
+ }
97
+ function runView(ctx, id, opts = {}) {
98
+ const v = getView(ctx, id);
99
+ return listRecords(ctx, v.object, { ...opts, viewId: id });
100
+ }
101
+ export {
102
+ createView,
103
+ deleteView,
104
+ duplicateView,
105
+ getView,
106
+ listViews,
107
+ runView,
108
+ updateView
109
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@fleox-agent-crm/agentcrm",
3
+ "version": "0.3.1",
4
+ "minSkillsVersion": "0.1.0",
5
+ "dataSchema": 1,
6
+ "repository": "github:fleox/agentcrm"
7
+ }
package/package.json CHANGED
@@ -1,6 +1,99 @@
1
1
  {
2
2
  "name": "@fleox-agent-crm/agentcrm",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.1",
4
+ "type": "module",
5
+ "description": "The static CRM your AI agent can run: a Twenty / HubSpot-style CRM that runs entirely in the browser or headless through the agentcrm CLI, with data on storage you own.",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "bin": {
11
+ "agentcrm": "dist/agent/agentcrm.mjs"
12
+ },
13
+ "files": [
14
+ "dist/agent",
15
+ "dist/admin",
16
+ "types/agentcrm-runtime.d.ts",
17
+ "dist/version.json",
18
+ "plugin",
19
+ "changelog.json",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "agentcrm": {
24
+ "minSkillsVersion": "0.1.0",
25
+ "dataSchema": 1
26
+ },
27
+ "scripts": {
28
+ "dev": "vite",
29
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.agent.json",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "build": "vite build && node scripts/write-admin-manifest.mjs && vite build --config vite.agent.config.ts && node scripts/write-version.mjs",
33
+ "build:examples": "node scripts/build-examples.mjs",
34
+ "preview": "vite preview",
35
+ "check:skills": "node scripts/check-skills.mjs",
36
+ "hermes:build": "node scripts/build-hermes.mjs",
37
+ "check:hermes": "node scripts/build-hermes.mjs --check && python3 -m unittest discover -s hermes/tests",
38
+ "version": "node scripts/sync-version.mjs && npm run build && node scripts/build-hermes.mjs && git add -A plugin hermes .claude-plugin",
39
+ "gen:runtime-stubs": "node scripts/gen-runtime-stubs.mjs",
40
+ "prepublishOnly": "npm run typecheck && npm test && npm run build && npm run check:skills"
41
+ },
42
+ "devDependencies": {
43
+ "@dnd-kit/core": "^6.3.1",
44
+ "@dnd-kit/sortable": "^10.0.0",
45
+ "@dnd-kit/utilities": "^3.2.2",
46
+ "@types/node": "^25.9.9",
47
+ "@types/papaparse": "^5.5.2",
48
+ "@types/react": "^18.3.31",
49
+ "@types/react-dom": "^18.3.7",
50
+ "@vitejs/plugin-react": "^5.2.0",
51
+ "autoprefixer": "^10.6.2",
52
+ "clsx": "^2.1.1",
53
+ "date-fns": "^4.4.0",
54
+ "dompurify": "^3.4.17",
55
+ "fake-indexeddb": "^6.2.7",
56
+ "firebase": "^11.10.0",
57
+ "happy-dom": "^20.14.6",
58
+ "i18next": "^23.16.8",
59
+ "i18next-browser-languagedetector": "^8.3.0",
60
+ "jszip": "^3.10.2",
61
+ "lucide-react": "^0.460.0",
62
+ "marked": "^18.1.3",
63
+ "minisearch": "^7.2.0",
64
+ "papaparse": "^5.7.0",
65
+ "postcss": "^8.5.32",
66
+ "react": "^18.3.1",
67
+ "react-dom": "^18.3.1",
68
+ "react-i18next": "^15.7.4",
69
+ "react-is": "^18.3.1",
70
+ "react-router-dom": "^6.30.6",
71
+ "recharts": "^3.10.1",
72
+ "tailwindcss": "^3.4.19",
73
+ "typescript": "^6.0.3",
74
+ "vite": "^6.4.5",
75
+ "vitest": "^4.1.12"
76
+ },
77
+ "repository": {
78
+ "type": "git",
79
+ "url": "git+https://github.com/fleox/agentcrm.git"
80
+ },
81
+ "homepage": "https://github.com/fleox/agentcrm#readme",
82
+ "keywords": [
83
+ "crm",
84
+ "static",
85
+ "mcp",
86
+ "ai-agent",
87
+ "claude",
88
+ "sales",
89
+ "pipeline",
90
+ "s3",
91
+ "encrypted"
92
+ ],
93
+ "publishConfig": {
94
+ "access": "public"
95
+ },
96
+ "bugs": {
97
+ "url": "https://github.com/fleox/agentcrm/issues"
98
+ }
99
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "agentcrm",
3
+ "version": "0.3.1",
4
+ "description": "Skills to install AgentCRM (the static CRM your AI agent can run), manage its sites, run and customise the CRM (modules, appearance, extensions), drive sales workflows and build extension modules and themes.",
5
+ "author": {
6
+ "name": "fleox"
7
+ },
8
+ "homepage": "https://github.com/fleox/agentcrm",
9
+ "repository": "https://github.com/fleox/agentcrm",
10
+ "license": "PolyForm-Noncommercial-1.0.0",
11
+ "keywords": [
12
+ "crm",
13
+ "sales",
14
+ "static",
15
+ "mcp"
16
+ ]
17
+ }