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

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 +57 -0
  4. package/dist/admin/admin-files.json +26 -0
  5. package/dist/admin/assets/chartsImpl-CE2akJat.js +91 -0
  6. package/dist/admin/assets/firebase-BHSUggRo.js +2 -0
  7. package/dist/admin/assets/gitJson-BulGh2KV.js +3 -0
  8. package/dist/admin/assets/index-DidVVK7L.js +1181 -0
  9. package/dist/admin/assets/index-hMXwHSvN.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-DEDlHCPj.js +6 -0
  15. package/dist/admin/assets/sdk-CnrLnlRo.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 +3932 -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-B6OqNVWp.mjs +97 -0
  30. package/dist/agent/chunks/appearance-BaShelzt.mjs +174 -0
  31. package/dist/agent/chunks/automations-BWrvLqP6.mjs +698 -0
  32. package/dist/agent/chunks/backup-ClSmxmFZ.mjs +103 -0
  33. package/dist/agent/chunks/batch-CVETiJj5.mjs +142 -0
  34. package/dist/agent/chunks/compact-CsFPaAAq.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-B5hRvkNm.mjs +95 -0
  40. package/dist/agent/chunks/extCheck--7lmVvl7.mjs +193 -0
  41. package/dist/agent/chunks/extPackage-BGl5Oqs8.mjs +115 -0
  42. package/dist/agent/chunks/extScaffold-DqxI7R1e.mjs +320 -0
  43. package/dist/agent/chunks/extensionActions-D2HtpQz4.mjs +48 -0
  44. package/dist/agent/chunks/extensions-BP1k60md.mjs +151 -0
  45. package/dist/agent/chunks/featureRegistry-C9nbVShp.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-q8Xu5bft.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-BKU5F9WF.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-DmE_sBch.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-CpHoUFtL.mjs +188 -0
  67. package/dist/agent/chunks/jsx-runtime-Ca2uwGDr.mjs +76 -0
  68. package/dist/agent/chunks/loader-C9nm3iwx.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-CqdVQVJb.mjs +177 -0
  73. package/dist/agent/chunks/nodeImport-BPCt5uMu.mjs +38 -0
  74. package/dist/agent/chunks/package-DWbn3t2R.mjs +194 -0
  75. package/dist/agent/chunks/papaparse-DjBYnQM2.mjs +1285 -0
  76. package/dist/agent/chunks/pipelines-DCdRBNBV.mjs +234 -0
  77. package/dist/agent/chunks/plan-C0TBrU92.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-DoqiT9xR.mjs +2191 -0
  81. package/dist/agent/chunks/registry-Ceexawxl.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-BB59N6ke.mjs +189 -0
  85. package/dist/agent/chunks/runtime-DHo7ZEEO.mjs +14852 -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-7-4-qtSS.mjs +203 -0
  89. package/dist/agent/chunks/schema-DlHt2PxI.mjs +367 -0
  90. package/dist/agent/chunks/sdk-whvfg786.mjs +43644 -0
  91. package/dist/agent/chunks/seed-CugPGYZL.mjs +523 -0
  92. package/dist/agent/chunks/server-ISwlDRCN.mjs +242 -0
  93. package/dist/agent/chunks/settings-BtvR_jdm.mjs +76 -0
  94. package/dist/agent/chunks/standardObjects-CheqfDqa.mjs +243 -0
  95. package/dist/agent/chunks/stats-CfeJssSS.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-Bew8lxKx.mjs +844 -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-fO_BM5U_.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 +76 -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,14 @@
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
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
8
+ function getDefaultExportFromCjs(x) {
9
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
10
+ }
11
+ export {
12
+ commonjsGlobal as c,
13
+ getDefaultExportFromCjs as g
14
+ };
@@ -0,0 +1,227 @@
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 { p as paginate } from "./query-C5nJB_3C.mjs";
9
+ import { A as ACTIVITY_TYPES } from "../agentcrm.mjs";
10
+ import { assertCan, OpsError, actorId, emit } from "./context-CxFfqS4D.mjs";
11
+ import { r as relationFields, a as relationIds, f as fileTargetPatch, b as fileCleanupMutations } from "./relations-B9TynBmA.mjs";
12
+ import { activitiesOf, recordOf, asDoc, requireActivity, objectsOf, recordsOf, userOf, fileOf } from "./store-5gqRSKXg.mjs";
13
+ import "./fields-B0bitgmr.mjs";
14
+ import "node:util";
15
+ import "node:fs";
16
+ import "node:path";
17
+ import "node:url";
18
+ import "node:crypto";
19
+ import "node:os";
20
+ import "node:child_process";
21
+ import "node:http";
22
+ import "./pluginRegistry-DyHtlkcr.mjs";
23
+ function normalizeAttachments(ctx, ids) {
24
+ const out = [];
25
+ for (const id of ids ?? []) {
26
+ const f = fileOf(ctx.store, id);
27
+ if (!f || f.deletedAt) throw new OpsError("validation", `Attachment "${id}" not found (upload it first).`);
28
+ if (!out.includes(f.id)) out.push(f.id);
29
+ }
30
+ return out;
31
+ }
32
+ function attachmentTargetMutations(ctx, activityId, added, removed) {
33
+ const out = [];
34
+ const target = { kind: "activity", id: activityId };
35
+ for (const id of added) {
36
+ const f = fileOf(ctx.store, id);
37
+ const m = f && fileTargetPatch(ctx, f, [target]);
38
+ if (m) out.push(m);
39
+ }
40
+ for (const id of removed) {
41
+ const f = fileOf(ctx.store, id);
42
+ const m = f && fileTargetPatch(ctx, f, [], [target]);
43
+ if (m) out.push(m);
44
+ }
45
+ return out;
46
+ }
47
+ function toMs(v) {
48
+ if (v === null || v === void 0 || v === "") return void 0;
49
+ if (typeof v === "number") return Number.isFinite(v) ? v : void 0;
50
+ const t = Date.parse(/^\d{4}-\d{2}-\d{2}$/.test(v) ? `${v}T09:00:00` : v);
51
+ if (Number.isNaN(t)) throw new OpsError("validation", `Invalid date "${v}".`);
52
+ return t;
53
+ }
54
+ function normalizeTargets(ctx, targets) {
55
+ const out = [];
56
+ for (const t of targets ?? []) {
57
+ const id = typeof t === "string" ? t : t.id;
58
+ const r = recordOf(ctx.store, id);
59
+ if (!r || r.deletedAt) throw new OpsError("validation", `Target record "${id}" not found.`);
60
+ if (!out.some((x) => x.id === r.id)) out.push({ object: r.object, id: r.id });
61
+ }
62
+ return out;
63
+ }
64
+ function checkAssignee(ctx, id) {
65
+ if (id && !userOf(ctx.store, id)) throw new OpsError("validation", `Unknown assignee "${id}".`);
66
+ }
67
+ function timelineScope(ctx, targetId, includeRelated) {
68
+ const ids = /* @__PURE__ */ new Set([targetId]);
69
+ if (!includeRelated) return ids;
70
+ const target = recordOf(ctx.store, targetId);
71
+ if (!target) return ids;
72
+ for (const object of objectsOf(ctx.store)) {
73
+ for (const field of relationFields(object)) {
74
+ if (field.relation.object !== target.object) continue;
75
+ for (const r of recordsOf(ctx.store, object.id)) if (relationIds(r.fields[field.id]).includes(targetId)) ids.add(r.id);
76
+ }
77
+ }
78
+ return ids;
79
+ }
80
+ function listActivities(ctx, opts = {}) {
81
+ assertCan(ctx, "activities.read");
82
+ let items = activitiesOf(ctx.store, { includeDeleted: opts.includeDeleted });
83
+ if (opts.target) {
84
+ const targetId = typeof opts.target === "string" ? opts.target : opts.target.id;
85
+ const scope = timelineScope(ctx, targetId, !!opts.includeRelated);
86
+ items = items.filter((a) => a.targets.some((t) => scope.has(t.id)));
87
+ }
88
+ const types = opts.types ?? (opts.type ? [opts.type] : void 0);
89
+ if (types) items = items.filter((a) => types.includes(a.type));
90
+ if (opts.assigneeId) items = items.filter((a) => a.assigneeId === opts.assigneeId);
91
+ if (opts.status === "open") items = items.filter((a) => !a.doneAt);
92
+ if (opts.status === "done") items = items.filter((a) => !!a.doneAt);
93
+ if (opts.dueBefore !== void 0) items = items.filter((a) => a.dueAt !== void 0 && a.dueAt < opts.dueBefore);
94
+ if (opts.dueAfter !== void 0) items = items.filter((a) => a.dueAt !== void 0 && a.dueAt >= opts.dueAfter);
95
+ if (opts.since !== void 0) items = items.filter((a) => a.createdAt >= opts.since);
96
+ if (opts.order === "due") {
97
+ items = [...items].sort((a, b) => (a.dueAt ?? Infinity) - (b.dueAt ?? Infinity) || a.createdAt - b.createdAt);
98
+ } else {
99
+ const at = (a) => typeof a.meta?.startAt === "number" ? a.meta.startAt : a.createdAt;
100
+ items = [...items].sort((a, b) => at(b) - at(a) || (a.id < b.id ? 1 : -1));
101
+ }
102
+ return paginate(items, { offset: opts.offset, limit: opts.limit });
103
+ }
104
+ function getActivity(ctx, id) {
105
+ assertCan(ctx, "activities.read");
106
+ return requireActivity(ctx.store, id);
107
+ }
108
+ async function addActivity(ctx, input, opts = {}) {
109
+ assertCan(ctx, "activities.write");
110
+ if (!ACTIVITY_TYPES.includes(input.type)) throw new OpsError("validation", `Unknown activity type "${input.type}".`);
111
+ const title = (input.title ?? "").trim() || (input.body ?? "").trim().split("\n")[0].slice(0, 80);
112
+ if (!title) throw new OpsError("validation", "An activity needs a title.");
113
+ checkAssignee(ctx, input.assigneeId);
114
+ const attachments = normalizeAttachments(ctx, input.attachments);
115
+ const now = ctx.now();
116
+ const activity = {
117
+ id: opts.id ?? newId(now),
118
+ type: input.type,
119
+ title,
120
+ ...input.body ? { body: input.body } : {},
121
+ targets: normalizeTargets(ctx, input.targets),
122
+ ...toMs(input.dueAt) !== void 0 ? { dueAt: toMs(input.dueAt) } : {},
123
+ ...input.doneAt ? { doneAt: input.doneAt } : {},
124
+ ...input.assigneeId ? { assigneeId: input.assigneeId } : input.type === "task" && actorId(ctx) ? { assigneeId: actorId(ctx) } : {},
125
+ ...input.meta ? { meta: input.meta } : {},
126
+ ...attachments.length ? { attachments } : {},
127
+ createdAt: now,
128
+ updatedAt: now,
129
+ ...actorId(ctx) ? { createdBy: actorId(ctx) } : {}
130
+ };
131
+ await ctx.store.write([{ op: "set", collection: "activities", doc: asDoc(activity) }, ...attachmentTargetMutations(ctx, activity.id, attachments, [])], { message: `Add ${activity.type}` });
132
+ const stored = requireActivity(ctx.store, activity.id);
133
+ if (!opts.silent) await emit(ctx, "activity.created", { activity: stored });
134
+ return stored;
135
+ }
136
+ async function addNote(ctx, target, body, title) {
137
+ assertCan(ctx, "activities.write");
138
+ const t = typeof target === "string" ? recordOf(ctx.store, target) : target;
139
+ if (!t) throw new OpsError("notFound", `Record "${String(target)}" not found.`);
140
+ return addActivity(ctx, { type: "note", title: title ?? "", body, targets: [{ object: t.object, id: t.id }] });
141
+ }
142
+ function createTask(ctx, input) {
143
+ return addActivity(ctx, { type: "task", ...input });
144
+ }
145
+ async function updateActivity(ctx, id, patch) {
146
+ assertCan(ctx, "activities.write");
147
+ const before = requireActivity(ctx.store, id);
148
+ const fields = { updatedAt: ctx.now() };
149
+ if (patch.title !== void 0) {
150
+ if (!patch.title.trim()) throw new OpsError("validation", "An activity needs a title.");
151
+ fields.title = patch.title.trim();
152
+ }
153
+ if (patch.body !== void 0) fields.body = patch.body || void 0;
154
+ if (patch.type !== void 0) {
155
+ if (!ACTIVITY_TYPES.includes(patch.type)) throw new OpsError("validation", `Unknown activity type "${patch.type}".`);
156
+ fields.type = patch.type;
157
+ }
158
+ if (patch.targets !== void 0) fields.targets = normalizeTargets(ctx, patch.targets);
159
+ if (patch.dueAt !== void 0) fields.dueAt = toMs(patch.dueAt);
160
+ if (patch.doneAt !== void 0) fields.doneAt = patch.doneAt ?? void 0;
161
+ if (patch.assigneeId !== void 0) {
162
+ checkAssignee(ctx, patch.assigneeId);
163
+ fields.assigneeId = patch.assigneeId ?? void 0;
164
+ }
165
+ if (patch.meta !== void 0) for (const [k, v] of Object.entries(patch.meta)) fields[`meta.${k}`] = v;
166
+ const extra = [];
167
+ if (patch.attachments !== void 0) {
168
+ const prev = before.attachments ?? [];
169
+ const next = normalizeAttachments(ctx, patch.attachments.filter((x) => !prev.includes(x)));
170
+ const kept = prev.filter((x) => patch.attachments.includes(x));
171
+ const all = [...kept, ...next];
172
+ fields.attachments = all.length ? all : void 0;
173
+ extra.push(...attachmentTargetMutations(ctx, id, next, prev.filter((x) => !all.includes(x))));
174
+ }
175
+ await ctx.store.write([{ op: "patch", collection: "activities", id, fields }, ...extra], { message: "Update activity" });
176
+ const activity = requireActivity(ctx.store, id);
177
+ await emit(ctx, "activity.updated", { activity, before });
178
+ if (!before.doneAt && activity.doneAt) await emit(ctx, "activity.completed", { activity });
179
+ return activity;
180
+ }
181
+ function completeTask(ctx, id, done = true) {
182
+ return updateActivity(ctx, id, { doneAt: done ? ctx.now() : null });
183
+ }
184
+ async function deleteActivity(ctx, id, opts = {}) {
185
+ assertCan(ctx, "activities.write");
186
+ requireActivity(ctx.store, id);
187
+ await ctx.store.write(
188
+ opts.hard ? [{ op: "delete", collection: "activities", id }, ...fileCleanupMutations(ctx, { activities: [id] })] : [{ op: "patch", collection: "activities", id, fields: { deletedAt: ctx.now(), updatedAt: ctx.now() } }],
189
+ { message: "Delete activity" }
190
+ );
191
+ return { id };
192
+ }
193
+ function listTasks(ctx, opts = {}) {
194
+ const now = ctx.now();
195
+ return listActivities(ctx, {
196
+ type: "task",
197
+ assigneeId: opts.assigneeId,
198
+ status: opts.status ?? "open",
199
+ target: opts.target,
200
+ dueBefore: opts.overdue ? now : opts.dueWithinDays !== void 0 ? now + opts.dueWithinDays * 864e5 : void 0,
201
+ order: "due",
202
+ limit: opts.limit,
203
+ offset: opts.offset
204
+ });
205
+ }
206
+ function lastActivityAt(ctx, recordId) {
207
+ let max;
208
+ for (const a of activitiesOf(ctx.store)) {
209
+ if (!a.targets.some((t) => t.id === recordId)) continue;
210
+ const at = Math.max(a.createdAt, a.doneAt ?? 0);
211
+ if (max === void 0 || at > max) max = at;
212
+ }
213
+ return max;
214
+ }
215
+ export {
216
+ addActivity,
217
+ addNote,
218
+ completeTask,
219
+ createTask,
220
+ deleteActivity,
221
+ getActivity,
222
+ lastActivityAt,
223
+ listActivities,
224
+ listTasks,
225
+ timelineScope,
226
+ updateActivity
227
+ };
@@ -0,0 +1,97 @@
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 MODULE_CATEGORIES = ["core", "sales", "productivity", "automation", "integrations", "ai", "customisation"];
8
+ function mod(id, m) {
9
+ return { id, name: `customize:modules.catalog.${id}.name`, description: `customize:modules.catalog.${id}.description`, ...m };
10
+ }
11
+ const BUILTIN_MODULES = [
12
+ mod("records", { label: "Records", summary: "Objects, records, table & kanban views, record pages.", icon: "Database", category: "core", required: true }),
13
+ mod("search", { label: "Search", summary: "Cmd+K command palette over records and navigation.", icon: "Search", category: "core", required: true }),
14
+ mod("settings", { label: "Settings", summary: "Workspace settings, data model, users, import / export.", icon: "Settings", category: "core", required: true }),
15
+ mod("setup", { label: "Setup & access", summary: "Setup wizard, sign-in, data backend, admin hosting, security.", icon: "ShieldCheck", category: "core", required: true }),
16
+ mod("dashboard", { label: "Dashboard", summary: "Home dashboard with KPIs, charts and widgets.", icon: "LayoutDashboard", category: "sales" }),
17
+ mod("deals", { label: "Deals & pipelines", summary: "The deals object, pipelines, kanban board, pipeline reports and widgets.", icon: "Handshake", category: "sales", objects: ["deals"], settingsSection: "pipelines" }),
18
+ mod("reports", { label: "Reports", summary: "Reports page: pipeline, forecast, won / lost, activity, lead sources.", icon: "BarChart3", category: "sales" }),
19
+ mod("forms", { label: "Lead forms", summary: "Static lead capture forms and inbox ingestion.", icon: "FileInput", category: "sales" }),
20
+ mod("tasks", { label: "Tasks", summary: "My tasks / all tasks page and the task overlays.", icon: "CheckSquare", category: "productivity" }),
21
+ mod("automations", { label: "Automations", summary: "Trigger → conditions → actions workflows and their run log.", icon: "Zap", category: "automation" }),
22
+ mod("integrations", { label: "Email & calendar", summary: "Gmail, Google Calendar and Outlook sync through browser OAuth.", icon: "Plug", category: "integrations", settingsSection: "integrations" }),
23
+ mod("assistant", { label: "AI assistant", summary: "Chat panel driving the AI tool catalog with your own Claude API key.", icon: "Sparkles", category: "ai", settingsSection: "assistant" }),
24
+ mod("customize", { label: "Customisation", summary: "Modules, extensions and appearance settings.", icon: "Palette", category: "customisation", required: true, settingsSection: "modules" })
25
+ ];
26
+ function builtinModule(id) {
27
+ return BUILTIN_MODULES.find((m) => m.id === id);
28
+ }
29
+ const REQUIRED_MODULES = BUILTIN_MODULES.filter((m) => m.required).map((m) => m.id);
30
+ const MODULES_CONFIG_ID = "modules";
31
+ function defaultDisabledModules() {
32
+ return BUILTIN_MODULES.filter((m) => m.defaultEnabled === false).map((m) => m.id);
33
+ }
34
+ function disabledFromDoc(doc) {
35
+ const raw = doc && typeof doc === "object" ? doc.disabled : void 0;
36
+ const list = Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : defaultDisabledModules();
37
+ return new Set(list.filter((id) => !REQUIRED_MODULES.includes(id)));
38
+ }
39
+ const modules = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
40
+ __proto__: null,
41
+ BUILTIN_MODULES,
42
+ MODULES_CONFIG_ID,
43
+ MODULE_CATEGORIES,
44
+ REQUIRED_MODULES,
45
+ builtinModule,
46
+ defaultDisabledModules,
47
+ disabledFromDoc
48
+ }, Symbol.toStringTag, { value: "Module" }));
49
+ const EXTENSION_API_VERSION = "1.0.0";
50
+ const EXTENSION_MIN_API_VERSION = "1.0.0";
51
+ const RUNTIME_GLOBAL = "__AGENTCRM_RUNTIME__";
52
+ const RUNTIME_MODULES = {
53
+ react: "react.js",
54
+ "react/jsx-runtime": "react-jsx-runtime.js",
55
+ "react-dom": "react-dom.js",
56
+ "react-dom/client": "react-dom-client.js",
57
+ "react-i18next": "react-i18next.js",
58
+ "lucide-react": "lucide-react.js",
59
+ "@agent-crm/runtime": "agentcrm-runtime.js"
60
+ };
61
+ const RUNTIME_SPECIFIERS = Object.keys(RUNTIME_MODULES);
62
+ const RUNTIME_DIR = "runtime";
63
+ const EXTENSION_LIMITS = {
64
+ bundle: 1.5 * 1024 * 1024,
65
+ style: 256 * 1024,
66
+ manifest: 16 * 1024,
67
+ zip: 4 * 1024 * 1024
68
+ };
69
+ function compareVersions(a, b) {
70
+ const parse = (s) => String(s).split("-")[0].split(".").slice(0, 3).map((p) => Number.parseInt(p, 10) || 0);
71
+ const x = parse(a);
72
+ const y = parse(b);
73
+ for (let i = 0; i < 3; i++) {
74
+ if ((x[i] ?? 0) !== (y[i] ?? 0)) return (x[i] ?? 0) < (y[i] ?? 0) ? -1 : 1;
75
+ }
76
+ return 0;
77
+ }
78
+ function isCompatibleApiVersion(version) {
79
+ return typeof version === "string" && /^\d+\.\d+\.\d+$/.test(version) && compareVersions(version, EXTENSION_MIN_API_VERSION) >= 0 && compareVersions(version, EXTENSION_API_VERSION) <= 0;
80
+ }
81
+ export {
82
+ BUILTIN_MODULES as B,
83
+ EXTENSION_API_VERSION as E,
84
+ MODULES_CONFIG_ID as M,
85
+ RUNTIME_SPECIFIERS as R,
86
+ EXTENSION_LIMITS as a,
87
+ EXTENSION_MIN_API_VERSION as b,
88
+ REQUIRED_MODULES as c,
89
+ disabledFromDoc as d,
90
+ builtinModule as e,
91
+ MODULE_CATEGORIES as f,
92
+ RUNTIME_MODULES as g,
93
+ RUNTIME_DIR as h,
94
+ isCompatibleApiVersion as i,
95
+ RUNTIME_GLOBAL as j,
96
+ modules as m
97
+ };
@@ -0,0 +1,174 @@
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 { m as mixHex, D as DEFAULT_ACCENT, r as resolveAppearance, A as APPEARANCE_DOC_ID, a as DEFAULT_APPEARANCE, v as validateAppearancePatch, b as validateImageDataUrl, c as APPEARANCE_KEYS } from "./schema-7-4-qtSS.mjs";
8
+ import { getExternalTheme } from "./themes-DPZFv3yc.mjs";
9
+ import { assertCan, OpsError } from "./context-CxFfqS4D.mjs";
10
+ import { extensionDocOf, extensionDocsOf } from "./store-5gqRSKXg.mjs";
11
+ import "./pluginRegistry-DyHtlkcr.mjs";
12
+ function surface(base, lift = 0.45) {
13
+ return { ...base, 850: mixHex(base[800], base[900], 0.5), 950: mixHex(base[950], base[900], lift) };
14
+ }
15
+ ({
16
+ slate: surface({ 50: "#f8fafc", 100: "#f1f5f9", 200: "#e2e8f0", 300: "#cbd5e1", 400: "#94a3b8", 500: "#64748b", 600: "#475569", 700: "#334155", 800: "#1e293b", 900: "#0f172a", 950: "#020617" }),
17
+ stone: surface({ 50: "#fafaf9", 100: "#f5f5f4", 200: "#e7e5e4", 300: "#d6d3d1", 400: "#a8a29e", 500: "#78716c", 600: "#57534e", 700: "#44403c", 800: "#292524", 900: "#1c1917", 950: "#0c0a09" }),
18
+ gray: surface({ 50: "#f9fafb", 100: "#f3f4f6", 200: "#e5e7eb", 300: "#d1d5db", 400: "#9ca3af", 500: "#6b7280", 600: "#4b5563", 700: "#374151", 800: "#1f2937", 900: "#111827", 950: "#030712" }),
19
+ neutral: surface({ 50: "#fafafa", 100: "#f5f5f5", 200: "#e5e5e5", 300: "#d4d4d4", 400: "#a3a3a3", 500: "#737373", 600: "#525252", 700: "#404040", 800: "#262626", 900: "#171717", 950: "#0a0a0a" })
20
+ });
21
+ const PRESETS = [
22
+ {
23
+ id: "default",
24
+ name: "Default",
25
+ description: "Neutral grays, blue accent, near-black buttons.",
26
+ values: { accent: DEFAULT_ACCENT, neutral: "zinc", radius: "md", density: "comfortable", font: "system", sidebar: "default", contrast: "normal", buttons: "neutral" }
27
+ },
28
+ {
29
+ id: "ocean",
30
+ name: "Ocean",
31
+ description: "Cool slate grays with a teal-blue accent.",
32
+ values: { accent: "#0891b2", neutral: "slate", radius: "lg", density: "comfortable", font: "system", sidebar: "default", contrast: "normal", buttons: "accent" }
33
+ },
34
+ {
35
+ id: "forest",
36
+ name: "Forest",
37
+ description: "Warm stone grays with a deep green accent and a dark sidebar.",
38
+ values: { accent: "#16a34a", neutral: "stone", radius: "md", density: "comfortable", font: "system", sidebar: "dark", contrast: "normal", buttons: "accent" }
39
+ },
40
+ {
41
+ id: "sunset",
42
+ name: "Sunset",
43
+ description: "Orange accent, soft rounded corners.",
44
+ values: { accent: "#ea580c", neutral: "stone", radius: "xl", density: "comfortable", font: "system", sidebar: "default", contrast: "normal", buttons: "accent" }
45
+ },
46
+ {
47
+ id: "graphite",
48
+ name: "Graphite",
49
+ description: "Monochrome, compact, dark sidebar — dense data work.",
50
+ values: { accent: "#52525b", neutral: "neutral", radius: "sm", density: "compact", font: "system", sidebar: "dark", contrast: "normal", buttons: "neutral" }
51
+ },
52
+ {
53
+ id: "rose",
54
+ name: "Rose",
55
+ description: "Rose accent with a colored sidebar.",
56
+ values: { accent: "#e11d48", neutral: "zinc", radius: "lg", density: "comfortable", font: "system", sidebar: "accent", contrast: "normal", buttons: "accent" }
57
+ },
58
+ {
59
+ id: "high-contrast",
60
+ name: "High contrast",
61
+ description: "Stronger borders and text, square corners — accessibility first.",
62
+ values: { accent: "#1d4ed8", neutral: "gray", radius: "sm", density: "comfortable", font: "system", sidebar: "default", contrast: "high", buttons: "neutral" }
63
+ }
64
+ ];
65
+ function findPreset(id) {
66
+ return PRESETS.find((p) => p.id === id);
67
+ }
68
+ const BRANDING_KEYS = ["logo", "favicon", "customCss"];
69
+ function getAppearanceDoc(ctx) {
70
+ assertCan(ctx, "settings.read");
71
+ return ctx.store.get("config", APPEARANCE_DOC_ID);
72
+ }
73
+ function getAppearance(ctx) {
74
+ const doc = getAppearanceDoc(ctx);
75
+ const theme = doc?.themeId && extensionDocOf(ctx.store, doc.themeId)?.enabled ? getExternalTheme(doc.themeId) : void 0;
76
+ return resolveAppearance(doc, theme);
77
+ }
78
+ function explicit(doc) {
79
+ if (!doc) return {};
80
+ return Object.fromEntries(Object.entries(doc).filter(([k, v]) => APPEARANCE_KEYS.includes(k) && v !== void 0));
81
+ }
82
+ async function writeDoc(ctx, values, message) {
83
+ const doc = { ...values, id: APPEARANCE_DOC_ID, updatedAt: ctx.now(), ...ctx.user?.id ? { updatedBy: ctx.user.id } : {} };
84
+ await ctx.store.write([{ op: "set", collection: "config", doc }], { message });
85
+ return getAppearance(ctx);
86
+ }
87
+ function assertTheme(ctx, id) {
88
+ const ext = extensionDocOf(ctx.store, id);
89
+ if (!ext || ext.kind !== "theme") {
90
+ const themes = extensionDocsOf(ctx.store).filter((d) => d.kind === "theme").map((d) => d.id);
91
+ throw new OpsError("notFound", `Theme "${id}" is not installed.${themes.length ? ` Installed themes: ${themes.join(", ")}.` : ""}`);
92
+ }
93
+ if (!ext.enabled) throw new OpsError("invalid", `Theme "${id}" is disabled — enable it first.`);
94
+ }
95
+ async function setAppearance(ctx, patch) {
96
+ assertCan(ctx, "appearance.write");
97
+ const { value, errors } = validateAppearancePatch(patch);
98
+ if (errors.length) throw new OpsError("validation", errors.join(" "), errors);
99
+ if (typeof value.themeId === "string") assertTheme(ctx, value.themeId);
100
+ if (typeof value.preset === "string" && value.preset !== "custom" && !findPreset(value.preset) && value.preset !== value.themeId && !extensionDocOf(ctx.store, value.preset)) {
101
+ throw new OpsError("validation", `Unknown preset "${value.preset}". Presets: ${PRESETS.map((p) => p.id).join(", ")}, custom.`);
102
+ }
103
+ const next = { ...explicit(getAppearanceDoc(ctx)) };
104
+ for (const [k, v] of Object.entries(value)) {
105
+ if (v === void 0) delete next[k];
106
+ else next[k] = v;
107
+ }
108
+ const visual = Object.keys(value).some((k) => !BRANDING_KEYS.includes(k) && k !== "preset" && k !== "defaultMode" && k !== "themeId");
109
+ if (visual && value.preset === void 0) next.preset = "custom";
110
+ return writeDoc(ctx, next, "Update appearance");
111
+ }
112
+ async function applyPreset(ctx, id) {
113
+ assertCan(ctx, "appearance.write");
114
+ const current = explicit(getAppearanceDoc(ctx));
115
+ const kept = {};
116
+ for (const k of BRANDING_KEYS) if (current[k] !== void 0) kept[k] = current[k];
117
+ const preset = findPreset(id);
118
+ if (preset) {
119
+ return writeDoc(ctx, { ...kept, ...current.defaultMode ? { defaultMode: current.defaultMode } : {}, ...preset.values, preset: preset.id }, `Apply appearance preset ${preset.name}`);
120
+ }
121
+ const ext = extensionDocOf(ctx.store, id);
122
+ if (ext?.kind === "theme") {
123
+ assertTheme(ctx, id);
124
+ return writeDoc(ctx, { ...kept, preset: id, themeId: id }, `Apply theme ${ext.manifest.name}`);
125
+ }
126
+ const themes = extensionDocsOf(ctx.store).filter((d) => d.kind === "theme").map((d) => d.id);
127
+ throw new OpsError("notFound", `Unknown preset "${id}". Presets: ${[...PRESETS.map((p) => p.id), ...themes].join(", ")}.`);
128
+ }
129
+ async function resetAppearance(ctx, opts = {}) {
130
+ assertCan(ctx, "appearance.write");
131
+ const current = explicit(getAppearanceDoc(ctx));
132
+ const kept = opts.branding ? {} : { ...current.logo ? { logo: current.logo } : {}, ...current.favicon ? { favicon: current.favicon } : {} };
133
+ if (!Object.keys(kept).length) {
134
+ if (getAppearanceDoc(ctx)) await ctx.store.write([{ op: "delete", collection: "config", id: APPEARANCE_DOC_ID }], { message: "Reset appearance" });
135
+ return getAppearance(ctx);
136
+ }
137
+ return writeDoc(ctx, kept, "Reset appearance");
138
+ }
139
+ async function setLogo(ctx, dataUrl, opts = {}) {
140
+ assertCan(ctx, "appearance.write");
141
+ const kind = opts.kind ?? "logo";
142
+ if (dataUrl !== null) {
143
+ const err = validateImageDataUrl(dataUrl, kind);
144
+ if (err) throw new OpsError("validation", err);
145
+ }
146
+ return setAppearance(ctx, { [kind]: dataUrl });
147
+ }
148
+ function listPresets(ctx) {
149
+ assertCan(ctx, "settings.read");
150
+ const builtin = PRESETS.map((p) => ({ id: p.id, name: p.name, description: p.description, source: "builtin", values: { ...DEFAULT_APPEARANCE, ...p.values, preset: p.id } }));
151
+ const themes = extensionDocsOf(ctx.store).filter((d) => d.kind === "theme").map((d) => {
152
+ const loaded = getExternalTheme(d.id);
153
+ return {
154
+ id: d.id,
155
+ name: loaded?.name ?? d.manifest.name,
156
+ description: loaded?.description ?? d.manifest.description,
157
+ source: "extension",
158
+ values: loaded ? { ...DEFAULT_APPEARANCE, ...loaded.appearance, preset: d.id, themeId: d.id } : { themeId: d.id },
159
+ enabled: !!d.enabled,
160
+ loaded: !!loaded,
161
+ version: d.manifest.version
162
+ };
163
+ });
164
+ return [...builtin, ...themes];
165
+ }
166
+ export {
167
+ applyPreset,
168
+ getAppearance,
169
+ getAppearanceDoc,
170
+ listPresets,
171
+ resetAppearance,
172
+ setAppearance,
173
+ setLogo
174
+ };