@fleox-agent-crm/agentcrm 0.8.0 → 0.9.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 (37) hide show
  1. package/README.md +16 -16
  2. package/changelog.json +9 -0
  3. package/dist/admin/admin-files.json +7 -7
  4. package/dist/admin/assets/{chartsImpl-C0T_ofB_.js → chartsImpl-D2PADqts.js} +1 -1
  5. package/dist/admin/assets/{firebase-EZazcubj.js → firebase-CwGe_Sf_.js} +2 -2
  6. package/dist/admin/assets/{gitJson-DUIDnXq1.js → gitJson-iOqViH3d.js} +1 -1
  7. package/dist/admin/assets/{index-D7BXqxSP.js → index-BgYXHsdo.js} +265 -265
  8. package/dist/admin/assets/{lucide-react.min-C8YfYPE0.js → lucide-react.min-DBYEZafa.js} +1 -1
  9. package/dist/admin/assets/{sdk-CpELytDH.js → sdk-DQ9ctNk3.js} +1 -1
  10. package/dist/admin/index.html +1 -1
  11. package/dist/agent/agentcrm.mjs +21 -21
  12. package/dist/agent/chunks/{extCheck-CKn2UubK.mjs → extCheck-yWx4BPsr.mjs} +3 -3
  13. package/dist/agent/chunks/{loader-DECxiKgQ.mjs → loader-CQwZ14Sl.mjs} +3 -3
  14. package/dist/agent/chunks/{registry-Bl9DqSxI.mjs → registry-D3C_myHO.mjs} +2 -2
  15. package/dist/agent/chunks/{runtime-DM81UQay.mjs → runtime-CImKXCKZ.mjs} +2 -2
  16. package/dist/agent/chunks/{schema-Nym-jiII.mjs → schema-CehJcGBp.mjs} +18 -0
  17. package/dist/agent/chunks/{schemaApply-DMFMdzSA.mjs → schemaApply-RJGX9KZk.mjs} +12 -9
  18. package/dist/agent/chunks/{server-D43hYW3q.mjs → server-876r03Db.mjs} +2 -2
  19. package/dist/agent/chunks/{tools-CfN0qrbo.mjs → tools-FJK-FGxt.mjs} +1 -1
  20. package/dist/version.json +1 -1
  21. package/package.json +1 -1
  22. package/plugin/.claude-plugin/plugin.json +1 -1
  23. package/plugin/skills/agentcrm-admin/SKILL.md +67 -67
  24. package/plugin/skills/agentcrm-admin/references/records.md +5 -5
  25. package/plugin/skills/agentcrm-admin/references/schema.md +19 -19
  26. package/plugin/skills/agentcrm-extensions/SKILL.md +8 -8
  27. package/plugin/skills/agentcrm-extensions/references/module-recipes.md +2 -2
  28. package/plugin/skills/agentcrm-extensions/references/testing.md +14 -14
  29. package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +3 -3
  30. package/plugin/skills/agentcrm-install/SKILL.md +13 -13
  31. package/plugin/skills/agentcrm-install/references/firebase.md +1 -1
  32. package/plugin/skills/agentcrm-install/references/github.md +1 -1
  33. package/plugin/skills/agentcrm-install/references/mcp.md +2 -2
  34. package/plugin/skills/agentcrm-install/references/plans.md +1 -1
  35. package/plugin/skills/agentcrm-install/references/s3.md +1 -1
  36. package/plugin/skills/agentcrm-manage/SKILL.md +15 -15
  37. package/plugin/skills/agentcrm-sales/SKILL.md +18 -18
@@ -1,4 +1,4 @@
1
- import{r as $v,g as eg}from"./index-D7BXqxSP.js";function tg(Ge,We){for(var e=0;e<We.length;e++){const h=We[e];if(typeof h!="string"&&!Array.isArray(h)){for(const r in h)if(r!=="default"&&!(r in Ge)){const Te=Object.getOwnPropertyDescriptor(h,r);Te&&Object.defineProperty(Ge,r,Te.get?Te:{enumerable:!0,get:()=>h[r]})}}}return Object.freeze(Object.defineProperty(Ge,Symbol.toStringTag,{value:"Module"}))}var Ze={exports:{}};/**
1
+ import{r as $v,g as eg}from"./index-BgYXHsdo.js";function tg(Ge,We){for(var e=0;e<We.length;e++){const h=We[e];if(typeof h!="string"&&!Array.isArray(h)){for(const r in h)if(r!=="default"&&!(r in Ge)){const Te=Object.getOwnPropertyDescriptor(h,r);Te&&Object.defineProperty(Ge,r,Te.get?Te:{enumerable:!0,get:()=>h[r]})}}}return Object.freeze(Object.defineProperty(Ge,Symbol.toStringTag,{value:"Module"}))}var Ze={exports:{}};/**
2
2
  * @license lucide-react v0.460.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,5 +1,5 @@
1
1
  const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index.esm-BFc7vwnl.js","./index.esm2017-EOzKbpUS.js"])))=>i.map(i=>d[i]);
2
- import{_ as kl}from"./index-D7BXqxSP.js";import"./index.esm-Dum0J07z.js";import{getAuth as xl,onAuthStateChanged as ho,signOut as Ol,sendEmailVerification as Ml,sendPasswordResetEmail as Fl,GoogleAuthProvider as Ll,signInWithPopup as Ul,signInWithEmailAndPassword as ql}from"./index.esm-CtEQZRb1.js";import{q as St,e as Ea,y as Ta,u as Vs,v as va,m as jl,t as Bl,F as zl,w as $l,x as Gl,L as Kl,z as qt,A as Ql,B as Wl,S as Hl,i as Xl,C as Yl,r as fo,h as Jl,g as Zl,n as tc}from"./index.esm2017-EOzKbpUS.js";import{withChangeTracking as ec,DELETE_FIELD as nc,SERVER_TIMESTAMP as rc,TS_FIELD as sc,splitTs as ic}from"./firebase-EZazcubj.js";var mo=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};/** @license
2
+ import{_ as kl}from"./index-BgYXHsdo.js";import"./index.esm-Dum0J07z.js";import{getAuth as xl,onAuthStateChanged as ho,signOut as Ol,sendEmailVerification as Ml,sendPasswordResetEmail as Fl,GoogleAuthProvider as Ll,signInWithPopup as Ul,signInWithEmailAndPassword as ql}from"./index.esm-CtEQZRb1.js";import{q as St,e as Ea,y as Ta,u as Vs,v as va,m as jl,t as Bl,F as zl,w as $l,x as Gl,L as Kl,z as qt,A as Ql,B as Wl,S as Hl,i as Xl,C as Yl,r as fo,h as Jl,g as Zl,n as tc}from"./index.esm2017-EOzKbpUS.js";import{withChangeTracking as ec,DELETE_FIELD as nc,SERVER_TIMESTAMP as rc,TS_FIELD as sc,splitTs as ic}from"./firebase-CwGe_Sf_.js";var mo=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};/** @license
3
3
  Copyright The Closure Library Authors.
4
4
  SPDX-License-Identifier: Apache-2.0
5
5
  */var Xt,Ia;(function(){var r;/** @license
@@ -120,7 +120,7 @@
120
120
  }
121
121
  }
122
122
  </script>
123
- <script type="module" crossorigin src="./assets/index-D7BXqxSP.js"></script>
123
+ <script type="module" crossorigin src="./assets/index-BgYXHsdo.js"></script>
124
124
  <link rel="stylesheet" crossorigin href="./assets/index-TcjySLVg.css">
125
125
  </head>
126
126
  <body>
@@ -142,7 +142,7 @@ const output = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
142
142
  toCliError
143
143
  }, Symbol.toStringTag, { value: "Module" }));
144
144
  const name = "@fleox-agent-crm/agentcrm";
145
- const version = "0.8.0";
145
+ const version = "0.9.0";
146
146
  const type = "module";
147
147
  const 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.";
148
148
  const license = "SEE LICENSE IN LICENSE";
@@ -524,7 +524,7 @@ function tmpFolder() {
524
524
  return tmpBase;
525
525
  }
526
526
  async function nodeImportBundle() {
527
- await import("./chunks/runtime-DM81UQay.mjs");
527
+ await import("./chunks/runtime-CImKXCKZ.mjs");
528
528
  const { createNodeImportBundle } = await import("./chunks/nodeImport-ylfRDvqt.mjs");
529
529
  return createNodeImportBundle({ runtimeDir: runtimeDir(), tmpDir: tmpFolder() });
530
530
  }
@@ -539,7 +539,7 @@ async function loadSessionExtensions(store, opts = {}) {
539
539
  if (!loadedAny && !opts.force && !hasEnabledExtensions(store)) return null;
540
540
  try {
541
541
  const importBundle = await nodeImportBundle();
542
- const { syncExtensions } = await import("./chunks/loader-DECxiKgQ.mjs");
542
+ const { syncExtensions } = await import("./chunks/loader-CQwZ14Sl.mjs");
543
543
  loadedAny = true;
544
544
  return await syncExtensions(store, { importBundle, onError: () => void 0 });
545
545
  } catch (err) {
@@ -553,7 +553,7 @@ async function loadSessionExtensions(store, opts = {}) {
553
553
  sync,
554
554
  async close() {
555
555
  if (!loadedAny) return;
556
- (await import("./chunks/registry-Bl9DqSxI.mjs")).deactivateAllExtensions();
556
+ (await import("./chunks/registry-D3C_myHO.mjs")).deactivateAllExtensions();
557
557
  }
558
558
  };
559
559
  }
@@ -2164,7 +2164,7 @@ async function check({ io, options, positionals }) {
2164
2164
  const kind = strOpt(options, "kind");
2165
2165
  if (kind && kind !== "module" && kind !== "theme") usage("--kind is module or theme.");
2166
2166
  const { readRawPackage } = await import("./chunks/extPackage-DuZ6GZhp.mjs");
2167
- const { checkExtension } = await import("./chunks/extCheck-CKn2UubK.mjs");
2167
+ const { checkExtension } = await import("./chunks/extCheck-yWx4BPsr.mjs");
2168
2168
  const raw = await readRawPackage(target);
2169
2169
  const report = await checkExtension(raw, { kind, callTools: !boolOpt(options, "no-call") });
2170
2170
  printResult(io, report, () => {
@@ -2211,7 +2211,7 @@ async function install({ io, options, positionals }) {
2211
2211
  const apply = options.yes === true;
2212
2212
  const disabled = boolOpt(options, "disabled");
2213
2213
  if (!boolOpt(options, "force")) {
2214
- const { checkExtension } = await import("./chunks/extCheck-CKn2UubK.mjs");
2214
+ const { checkExtension } = await import("./chunks/extCheck-yWx4BPsr.mjs");
2215
2215
  const report = await checkExtension(raw, { callTools: false });
2216
2216
  if (!report.valid) {
2217
2217
  throw new CliError(
@@ -2247,7 +2247,7 @@ async function install({ io, options, positionals }) {
2247
2247
  }
2248
2248
  const result = await ext.installExtension(s.ctx, pkg2, disabled ? { enabled: false } : {});
2249
2249
  const report = await s.extensions.sync();
2250
- const { getLoadedExtension } = await import("./chunks/registry-Bl9DqSxI.mjs");
2250
+ const { getLoadedExtension } = await import("./chunks/registry-D3C_myHO.mjs");
2251
2251
  const loaded = getLoadedExtension(m.id);
2252
2252
  const failure = report?.failed.find((f) => f.id === m.id || f.id === "*");
2253
2253
  if (failure && !loaded) return { ...result, author: m.author ?? null, load: { status: "error", error: failure.error } };
@@ -2309,7 +2309,7 @@ const extCommand = {
2309
2309
  if (kind && kind !== "module" && kind !== "theme") usage("--kind is module or theme.");
2310
2310
  return withSession(io, options, {}, async (s) => {
2311
2311
  const { listExtensions } = await import("./chunks/extensions-Bp72uZ9a.mjs");
2312
- const { getLoadedExtension } = await import("./chunks/registry-Bl9DqSxI.mjs");
2312
+ const { getLoadedExtension } = await import("./chunks/registry-D3C_myHO.mjs");
2313
2313
  return listExtensions(s.ctx, kind ? { kind } : {}).map((e) => ({ ...e, load: s.extensions.safeMode ? "skipped" : getLoadedExtension(e.id)?.status ?? (e.enabled ? "not loaded" : "disabled"), ...getLoadedExtension(e.id)?.error ? { loadError: getLoadedExtension(e.id)?.error } : {} }));
2314
2314
  }, (rows) => table(rows.map((r) => ({ ...r, enabled: r.enabled ? "yes" : "no" })), ["id", "kind", "name", "version", "enabled", "load", "author"]));
2315
2315
  }
@@ -3515,13 +3515,13 @@ const objectsCommand = {
3515
3515
  switch (action) {
3516
3516
  case "list":
3517
3517
  return withSession(io, options, {}, async ({ ctx, store }) => {
3518
- const { listObjects } = await import("./chunks/schema-Nym-jiII.mjs");
3518
+ const { listObjects } = await import("./chunks/schema-CehJcGBp.mjs");
3519
3519
  const { recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
3520
3520
  return listObjects(ctx).map((o) => ({ id: o.id, labelSingular: o.labelSingular, labelPlural: o.labelPlural, standard: o.standard, labelField: o.labelField, fields: o.fields.length, records: recordsOf(store, o.id).length }));
3521
3521
  }, (rows) => table(rows, ["id", "labelPlural", "fields", "records", "standard"]));
3522
3522
  case "get": {
3523
3523
  const objectId = positional(positionals, 1, "object id", "objects get <id>");
3524
- return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/schema-Nym-jiII.mjs")).describeSchema(ctx, objectId)[0]);
3524
+ return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/schema-CehJcGBp.mjs")).describeSchema(ctx, objectId)[0]);
3525
3525
  }
3526
3526
  case "create": {
3527
3527
  const data = jsonObjectOpt(options, "data") ?? {};
@@ -3534,7 +3534,7 @@ const objectsCommand = {
3534
3534
  ...strOpt(options, "color") ? { color: strOpt(options, "color") } : {}
3535
3535
  };
3536
3536
  if (!input.labelSingular || !input.labelPlural) usage("objects create needs --singular and --plural (or --data).");
3537
- return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-Nym-jiII.mjs")).createObject(ctx, input));
3537
+ return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-CehJcGBp.mjs")).createObject(ctx, input));
3538
3538
  }
3539
3539
  case "update": {
3540
3540
  const objectId = positional(positionals, 1, "object id", "objects update <id> …");
@@ -3546,12 +3546,12 @@ const objectsCommand = {
3546
3546
  ...strOpt(options, "label-field") ? { labelField: strOpt(options, "label-field") } : {}
3547
3547
  };
3548
3548
  if (!Object.keys(patch).length) usage("objects update needs --singular, --plural, --icon, --color or --label-field.");
3549
- return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-Nym-jiII.mjs")).updateObject(ctx, objectId, patch));
3549
+ return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-CehJcGBp.mjs")).updateObject(ctx, objectId, patch));
3550
3550
  }
3551
3551
  case "delete": {
3552
3552
  if (!id) usage("objects delete needs an object id.");
3553
3553
  return withSession(io, options, { lock: options.yes === true }, async ({ ctx, store }) => {
3554
- const { getObject, deleteObject } = await import("./chunks/schema-Nym-jiII.mjs");
3554
+ const { getObject, deleteObject } = await import("./chunks/schema-CehJcGBp.mjs");
3555
3555
  const { recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
3556
3556
  const o = getObject(ctx, id);
3557
3557
  const plan = { object: o.id, label: o.labelPlural, standard: o.standard, recordsDeleted: recordsOf(store, o.id, { includeDeleted: true }).length };
@@ -3609,7 +3609,7 @@ const fieldsCommand = {
3609
3609
  ...boolOpt(options, "unique") ? { unique: true } : {},
3610
3610
  ...strOpt(options, "description") ? { description: strOpt(options, "description") } : {}
3611
3611
  };
3612
- return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-Nym-jiII.mjs")).createField(ctx, objectId, input));
3612
+ return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-CehJcGBp.mjs")).createField(ctx, objectId, input));
3613
3613
  }
3614
3614
  case "update": {
3615
3615
  if (!fieldId) usage("fields update needs a field id.");
@@ -3626,12 +3626,12 @@ const fieldsCommand = {
3626
3626
  ...strOpt(options, "description") !== void 0 ? { description: strOpt(options, "description") } : {}
3627
3627
  };
3628
3628
  if (!Object.keys(patch).length) usage("fields update needs at least one change.");
3629
- return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-Nym-jiII.mjs")).updateField(ctx, objectId, fieldId, patch));
3629
+ return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-CehJcGBp.mjs")).updateField(ctx, objectId, fieldId, patch));
3630
3630
  }
3631
3631
  case "delete": {
3632
3632
  if (!fieldId) usage("fields delete needs a field id.");
3633
3633
  return withSession(io, options, { lock: options.yes === true }, async ({ ctx, store }) => {
3634
- const { getObject, deleteField } = await import("./chunks/schema-Nym-jiII.mjs");
3634
+ const { getObject, deleteField } = await import("./chunks/schema-CehJcGBp.mjs");
3635
3635
  const { recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
3636
3636
  const field = getObject(ctx, objectId).fields.find((f) => f.id === fieldId);
3637
3637
  if (!field) usage(`No field "${fieldId}" on ${objectId}.`, `\`agentcrm objects get ${objectId}\` lists them.`);
@@ -3664,7 +3664,7 @@ const schemaCommand = {
3664
3664
  usage(`The schema is not valid JSON: ${err.message}`);
3665
3665
  }
3666
3666
  const apply = options.yes === true;
3667
- const { applySchema, parseSchemaSpec } = await import("./chunks/schemaApply-DMFMdzSA.mjs");
3667
+ const { applySchema, parseSchemaSpec } = await import("./chunks/schemaApply-RJGX9KZk.mjs");
3668
3668
  const spec = parseSchemaSpec(raw);
3669
3669
  return withSession(
3670
3670
  io,
@@ -3982,7 +3982,7 @@ const toolsCommand = {
3982
3982
  async run({ io, options, positionals }) {
3983
3983
  const [action = "list"] = positionals;
3984
3984
  if (action === "list") {
3985
- const { listAiTools, AI_TOOLS } = await import("./chunks/tools-CfN0qrbo.mjs");
3985
+ const { listAiTools, AI_TOOLS } = await import("./chunks/tools-FJK-FGxt.mjs");
3986
3986
  const builtin = new Set(AI_TOOLS.map((t) => t.name));
3987
3987
  const shape = () => listAiTools().map((t) => ({ name: t.name, description: t.description, mutating: t.mutating, source: builtin.has(t.name) ? "builtin" : "extension", inputSchema: t.inputSchema }));
3988
3988
  const human = (r) => table(r.tools, ["name", "mutating", "source", "description"]);
@@ -4002,7 +4002,7 @@ const toolsCommand = {
4002
4002
  }
4003
4003
  if (action === "call") {
4004
4004
  const name2 = positional(positionals, 1, "tool name", "tools call <name> --input <json>");
4005
- const { findTool, callTool, listAiTools } = await import("./chunks/tools-CfN0qrbo.mjs");
4005
+ const { findTool, callTool, listAiTools } = await import("./chunks/tools-FJK-FGxt.mjs");
4006
4006
  const input = jsonObjectOpt(options, "input") ?? {};
4007
4007
  const builtin = findTool(name2);
4008
4008
  return withSession(io, options, { lock: builtin ? builtin.mutating : true }, async ({ ctx }) => {
@@ -4024,8 +4024,8 @@ const mcpCommand = {
4024
4024
  const log = (msg) => process.stderr.write(`${msg}
4025
4025
  `);
4026
4026
  for (const w of session2.warnings) log(`[agentcrm mcp] note: ${w}`);
4027
- const { listAiTools } = await import("./chunks/tools-CfN0qrbo.mjs");
4028
- const { createMcpServer, serveStdio } = await import("./chunks/server-D43hYW3q.mjs");
4027
+ const { listAiTools } = await import("./chunks/tools-FJK-FGxt.mjs");
4028
+ const { createMcpServer, serveStdio } = await import("./chunks/server-876r03Db.mjs");
4029
4029
  let lastRefresh = Date.now();
4030
4030
  const server = createMcpServer({
4031
4031
  readOnly,
@@ -95,9 +95,9 @@ async function loadInSandbox(report, manifest, files, opts) {
95
95
  import("./pluginRegistry-DyHtlkcr.mjs"),
96
96
  import("./seed-Bb26Zsni.mjs"),
97
97
  import("./store-5gqRSKXg.mjs"),
98
- import("./loader-DECxiKgQ.mjs"),
99
- import("./registry-Bl9DqSxI.mjs"),
100
- import("./tools-CfN0qrbo.mjs"),
98
+ import("./loader-CQwZ14Sl.mjs"),
99
+ import("./registry-D3C_myHO.mjs"),
100
+ import("./tools-FJK-FGxt.mjs"),
101
101
  import("./extensionActions-D2HtpQz4.mjs"),
102
102
  import("./featureRegistry-DSsZbhrh.mjs"),
103
103
  import("./themes-DPZFv3yc.mjs"),
@@ -6,7 +6,7 @@ const __filename = __acrmPath(import.meta.url);
6
6
  const __dirname = __acrmDirname(__filename);
7
7
  import { j as RUNTIME_DIR, h as RUNTIME_MODULES, i as isCompatibleApiVersion, k as RUNTIME_GLOBAL } from "./api-Cz0Ubj-B.mjs";
8
8
  import { rewriteRuntimeImports, fingerprint, bundleImports } from "./package-B7mI6HGi.mjs";
9
- import { listLoadedExtensions, deactivateExtension, getLoadedExtension, setExtensionStatus, activateExtension } from "./registry-Bl9DqSxI.mjs";
9
+ import { listLoadedExtensions, deactivateExtension, getLoadedExtension, setExtensionStatus, activateExtension } from "./registry-D3C_myHO.mjs";
10
10
  import "./index-w03ReRs4.mjs";
11
11
  import "./_commonjsHelpers-ClciMIcB.mjs";
12
12
  import "stream";
@@ -22,7 +22,7 @@ import "./pluginRegistry-DyHtlkcr.mjs";
22
22
  import "./settings-Di8nzNEL.mjs";
23
23
  import "./store-5gqRSKXg.mjs";
24
24
  import "./runtimeConfig-CCOFg1RM.mjs";
25
- import "./tools-CfN0qrbo.mjs";
25
+ import "./tools-FJK-FGxt.mjs";
26
26
  import "./fields-B0bitgmr.mjs";
27
27
  import "./query-C5nJB_3C.mjs";
28
28
  import "../agentcrm.mjs";
@@ -45,7 +45,7 @@ import "./records-BJLSmv0O.mjs";
45
45
  import "./standardObjects-vrmqIVLH.mjs";
46
46
  import "./pipelines-G-c23x-s.mjs";
47
47
  import "./reports-ogUa41jr.mjs";
48
- import "./schema-Nym-jiII.mjs";
48
+ import "./schema-CehJcGBp.mjs";
49
49
  import "./automations-gCDYNS88.mjs";
50
50
  import "./extensionActions-D2HtpQz4.mjs";
51
51
  import "./forms-Bb0zztBM.mjs";
@@ -6,7 +6,7 @@ const __filename = __acrmPath(import.meta.url);
6
6
  const __dirname = __acrmDirname(__filename);
7
7
  import { i as isCompatibleApiVersion } from "./api-Cz0Ubj-B.mjs";
8
8
  import { registerExternalFeature } from "./featureRegistry-DSsZbhrh.mjs";
9
- import { registerAiTool } from "./tools-CfN0qrbo.mjs";
9
+ import { registerAiTool } from "./tools-FJK-FGxt.mjs";
10
10
  import { registerAutomationAction } from "./extensionActions-D2HtpQz4.mjs";
11
11
  import { plugins } from "./pluginRegistry-DyHtlkcr.mjs";
12
12
  import { registerExternalTheme } from "./themes-DPZFv3yc.mjs";
@@ -41,7 +41,7 @@ import "./records-BJLSmv0O.mjs";
41
41
  import "./standardObjects-vrmqIVLH.mjs";
42
42
  import "./pipelines-G-c23x-s.mjs";
43
43
  import "./reports-ogUa41jr.mjs";
44
- import "./schema-Nym-jiII.mjs";
44
+ import "./schema-CehJcGBp.mjs";
45
45
  import "./automations-gCDYNS88.mjs";
46
46
  import "./forms-Bb0zztBM.mjs";
47
47
  import "./schema-DnLj8dUO.mjs";
@@ -12,7 +12,7 @@ import { bulkDelete, bulkUpdate, createRecord, deleteRecord, getRecord, getRecor
12
12
  import { j as expandRelations, b as fileCleanupMutations, g as fileFieldIds, h as fileIdsIn, d as fileMergeMutations, f as fileTargetPatch, i as inverseRelations, l as labelOf, k as linkRecords, e as referencedFileIds, m as relatedRecords, r as relationFields, a as relationIds, c as rewriteReferences, s as sameTarget, t as toRef, u as unlinkRecords, v as validateRelationValue } from "./relations-bmUKPT0G.mjs";
13
13
  import { addActivity, addNote, completeTask, createTask, deleteActivity, getActivity, lastActivityAt, listActivities, listTasks, timelineScope, updateActivity } from "./activities-be260oPg.mjs";
14
14
  import { createPipeline, deletePipeline, forecast, getPipeline, listPipelines, moveStage, pipelineOfRecord, syncPipelineOptions, updatePipeline } from "./pipelines-G-c23x-s.mjs";
15
- import { addOption, changeFieldType, createField, createObject, deleteField, deleteObject, describeSchema, getObject, listObjects, removeOption, reorderFields, updateField, updateObject, updateOption } from "./schema-Nym-jiII.mjs";
15
+ import { addOption, changeFieldType, createField, createObject, deleteField, deleteObject, describeSchema, getObject, listObjects, removeOption, reorderFields, updateField, updateObject, updateOption } from "./schema-CehJcGBp.mjs";
16
16
  import { createView, deleteView, duplicateView, getView, listViews, runView, updateView } from "./views-zRdsphZl.mjs";
17
17
  import { createUser, deleteUser, findUserByEmail, getUser, listUsers, setUserRole, updateUser } from "./users-DI1BvS0f.mjs";
18
18
  import { DEFAULT_SETTINGS, SETTINGS_KEYS, assertNoSecrets, getConfigDoc, getSettings, setConfigDoc, updateSettings } from "./settings-Di8nzNEL.mjs";
@@ -41,7 +41,7 @@ import { isEmptyFieldValue, formatFieldValue, formatAddress, dateValueToMs, form
41
41
  import { fileKind, isPreviewable, formatBytes } from "./files-CjsPJSR6.mjs";
42
42
  import { plugins } from "./pluginRegistry-DyHtlkcr.mjs";
43
43
  import { n as newId } from "./ids-CvnmrMJX.mjs";
44
- import { registerAiTool } from "./tools-CfN0qrbo.mjs";
44
+ import { registerAiTool } from "./tools-FJK-FGxt.mjs";
45
45
  import { a as DEFAULT_APPEARANCE } from "./schema-DnLj8dUO.mjs";
46
46
  import { b as EXTENSION_MIN_API_VERSION, E as EXTENSION_API_VERSION, k as RUNTIME_GLOBAL } from "./api-Cz0Ubj-B.mjs";
47
47
  import "./query-C5nJB_3C.mjs";
@@ -147,6 +147,22 @@ function checkDrilldown(ctx, objectId, d) {
147
147
  }
148
148
  return { object: d.object, field: d.field };
149
149
  }
150
+ function checkRollup(ctx, objectId, r) {
151
+ const child = requireObject(ctx.store, r.object);
152
+ const via = child.fields.find((f) => f.id === r.via);
153
+ if (!via || via.type !== "relation" || via.relation?.object !== objectId) {
154
+ throw new OpsError("validation", `Rollup: ${child.labelPlural} has no relation field "${r.via}" pointing at ${objectId}.`);
155
+ }
156
+ if (!child.fields.some((f) => f.id === r.field)) throw new OpsError("validation", `Rollup: ${child.labelPlural} has no field "${r.field}".`);
157
+ if (r.scope) {
158
+ const own = requireObject(ctx.store, objectId).fields.find((f) => f.id === r.scope.field);
159
+ const theirs = child.fields.find((f) => f.id === r.scope.via);
160
+ if (!own || own.type !== "relation" || !theirs || theirs.type !== "relation" || own.relation?.object !== theirs.relation?.object) {
161
+ throw new OpsError("validation", `Rollup scope: "${r.scope.field}" and ${child.labelPlural}."${r.scope.via}" must be relations to the same object.`);
162
+ }
163
+ }
164
+ return { object: r.object, via: r.via, field: r.field, ...r.scope ? { scope: { field: r.scope.field, via: r.scope.via } } : {}, ...r.where?.length ? { where: r.where } : {} };
165
+ }
150
166
  function buildOptions(input, existing = []) {
151
167
  const out = [];
152
168
  (input ?? []).forEach((o, i) => {
@@ -185,6 +201,7 @@ function buildField(ctx, object, input) {
185
201
  }
186
202
  if (input.defaultValue !== void 0) field.defaultValue = input.defaultValue;
187
203
  if (input.drilldown) field.drilldown = checkDrilldown(ctx, object.id, input.drilldown);
204
+ if (input.rollup) field.rollup = checkRollup(ctx, object.id, input.rollup);
188
205
  return field;
189
206
  }
190
207
  async function createField(ctx, objectId, input) {
@@ -229,6 +246,7 @@ async function updateField(ctx, objectId, fieldId, patch) {
229
246
  if (patch.currency !== void 0) field.currency = patch.currency.toUpperCase();
230
247
  if (patch.defaultValue !== void 0) field.defaultValue = patch.defaultValue;
231
248
  if (patch.drilldown !== void 0) field.drilldown = patch.drilldown ? checkDrilldown(ctx, objectId, patch.drilldown) : void 0;
249
+ if (patch.rollup !== void 0) field.rollup = patch.rollup ? checkRollup(ctx, objectId, patch.rollup) : void 0;
232
250
  const mutations = [];
233
251
  let converted;
234
252
  let cleared;
@@ -6,7 +6,7 @@ const __filename = __acrmPath(import.meta.url);
6
6
  const __dirname = __acrmDirname(__filename);
7
7
  import { OpsError, assertCan } from "./context-CxFfqS4D.mjs";
8
8
  import { listPipelines, createPipeline, updatePipeline } from "./pipelines-G-c23x-s.mjs";
9
- import { listObjects, createObject, updateObject, createField, updateField } from "./schema-Nym-jiII.mjs";
9
+ import { listObjects, createObject, updateObject, createField, updateField } from "./schema-CehJcGBp.mjs";
10
10
  import { listViews, createView, updateView } from "./views-zRdsphZl.mjs";
11
11
  import "./pluginRegistry-DyHtlkcr.mjs";
12
12
  import "./fields-B0bitgmr.mjs";
@@ -50,8 +50,8 @@ function missingOptions(field, wanted) {
50
50
  const have = new Set((field.options ?? []).map((o) => o.label.toLowerCase()));
51
51
  return (wanted ?? []).map((o) => typeof o === "string" ? o : o.label ?? "").filter((l) => l && !have.has(l.toLowerCase()));
52
52
  }
53
- function withoutDrilldown(f) {
54
- const { drilldown: _drilldown, ...rest } = f;
53
+ function withoutLinks(f) {
54
+ const { drilldown: _drilldown, rollup: _rollup, ...rest } = f;
55
55
  return rest;
56
56
  }
57
57
  function fieldPatch(field, spec) {
@@ -77,7 +77,7 @@ async function applySchema(ctx, spec) {
77
77
  let current = listObjects(ctx).find((x) => x.id === o.id);
78
78
  const fields = o.fields ?? [];
79
79
  if (!current) {
80
- const plain = fields.filter((f) => f.type !== "relation" && f.id !== "name").map(withoutDrilldown);
80
+ const plain = fields.filter((f) => f.type !== "relation" && f.id !== "name").map(withoutLinks);
81
81
  current = await createObject(ctx, { id: o.id, labelSingular: o.labelSingular, labelPlural: o.labelPlural, icon: o.icon, color: o.color, fields: plain });
82
82
  report.changes.push({ kind: "object", action: "create", target: o.id, changes: plain.map((f) => f.id) });
83
83
  } else {
@@ -98,7 +98,7 @@ async function applySchema(ctx, spec) {
98
98
  const current2 = listObjects(ctx).find((x) => x.id === o.id);
99
99
  const field = current2.fields.find((x) => x.id === f.id);
100
100
  if (!field) {
101
- await createField(ctx, o.id, withoutDrilldown(f));
101
+ await createField(ctx, o.id, withoutLinks(f));
102
102
  report.changes.push({ kind: "field", action: "create", target: `${o.id}.${f.id}`, changes: [f.type] });
103
103
  continue;
104
104
  }
@@ -126,11 +126,14 @@ async function applySchema(ctx, spec) {
126
126
  }
127
127
  for (const o of spec.objects ?? []) {
128
128
  for (const f of o.fields ?? []) {
129
- if (f.drilldown === void 0) continue;
130
129
  const field = listObjects(ctx).find((x) => x.id === o.id)?.fields.find((x) => x.id === f.id);
131
- if (!field || field.type !== f.type || same(f.drilldown, field.drilldown)) continue;
132
- await updateField(ctx, o.id, f.id, { drilldown: f.drilldown });
133
- report.changes.push({ kind: "field", action: "update", target: `${o.id}.${f.id}`, changes: ["drilldown"] });
130
+ if (!field || field.type !== f.type) continue;
131
+ const patch = {};
132
+ if (f.drilldown !== void 0 && !same(f.drilldown, field.drilldown)) patch.drilldown = f.drilldown;
133
+ if (f.rollup !== void 0 && !same(f.rollup, field.rollup)) patch.rollup = f.rollup;
134
+ if (!Object.keys(patch).length) continue;
135
+ await updateField(ctx, o.id, f.id, patch);
136
+ report.changes.push({ kind: "field", action: "update", target: `${o.id}.${f.id}`, changes: Object.keys(patch) });
134
137
  }
135
138
  }
136
139
  for (const p of spec.pipelines ?? []) {
@@ -97,7 +97,7 @@ function createMcpServer(opts) {
97
97
  try {
98
98
  const run = async () => {
99
99
  const ctx = await opts.backend.context();
100
- const { callTool: call } = await import("./tools-CfN0qrbo.mjs");
100
+ const { callTool: call } = await import("./tools-FJK-FGxt.mjs");
101
101
  return call(ctx, name, args);
102
102
  };
103
103
  const result = tool.mutating ? await opts.backend.withWrite(run) : await run();
@@ -112,7 +112,7 @@ function createMcpServer(opts) {
112
112
  async function readResource(id, uri) {
113
113
  const ctx = await opts.backend.context();
114
114
  let value;
115
- if (uri === "agentcrm://schema") value = (await import("./schema-Nym-jiII.mjs")).describeSchema(ctx);
115
+ if (uri === "agentcrm://schema") value = (await import("./schema-CehJcGBp.mjs")).describeSchema(ctx);
116
116
  else if (uri === "agentcrm://pipelines") {
117
117
  const { listPipelines, forecast } = await import("./pipelines-G-c23x-s.mjs");
118
118
  value = listPipelines(ctx).map((p) => ({ ...p, forecast: forecast(ctx, { pipelineId: p.id }) }));
@@ -14,7 +14,7 @@ import { importCsv } from "./importCsv-BuSYG4ja.mjs";
14
14
  import { moveStage, forecast, listPipelines } from "./pipelines-G-c23x-s.mjs";
15
15
  import { getRecord, searchRecords, listRecords, getRecordDetails, createRecord, updateRecord, deleteRecord, queryContext } from "./records-BJLSmv0O.mjs";
16
16
  import { runReport, REPORTS } from "./reports-ogUa41jr.mjs";
17
- import { describeSchema, createField } from "./schema-Nym-jiII.mjs";
17
+ import { describeSchema, createField } from "./schema-CehJcGBp.mjs";
18
18
  import { objectOf, recordOf, userOf, activitiesOf, fileOf } from "./store-5gqRSKXg.mjs";
19
19
  import { ACTION_TYPES, TRIGGER_TYPES, listAutomationRuns, AUTOMATION_TEMPLATES, listAutomations, createAutomationFromTemplate, createAutomation, setAutomationEnabled, testAutomation, runScheduled } from "./automations-gCDYNS88.mjs";
20
20
  import { listForms, ingestInbox } from "./forms-Bb0zztBM.mjs";
package/dist/version.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleox-agent-crm/agentcrm",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "minSkillsVersion": "0.1.0",
5
5
  "dataSchema": 1,
6
6
  "repository": "github:fleox/agentcrm"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleox-agent-crm/agentcrm",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
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
6
  "license": "SEE LICENSE IN LICENSE",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentcrm",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
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
5
  "author": {
6
6
  "name": "fleox"