@fleox-agent-crm/agentcrm 0.7.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 +19 -0
  3. package/dist/admin/admin-files.json +7 -7
  4. package/dist/admin/assets/{chartsImpl-Cx0bQmYg.js → chartsImpl-D2PADqts.js} +1 -1
  5. package/dist/admin/assets/{firebase-DyAT9e1o.js → firebase-CwGe_Sf_.js} +2 -2
  6. package/dist/admin/assets/{gitJson-BeyPO6eJ.js → gitJson-iOqViH3d.js} +1 -1
  7. package/dist/admin/assets/{index-Bp5AxImK.js → index-BgYXHsdo.js} +270 -270
  8. package/dist/admin/assets/{lucide-react.min-BXJHmaO2.js → lucide-react.min-DBYEZafa.js} +1 -1
  9. package/dist/admin/assets/{sdk-hs3heWPk.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-Bu8C87OV.mjs → extCheck-yWx4BPsr.mjs} +3 -3
  13. package/dist/agent/chunks/{loader-CGIek5YG.mjs → loader-CQwZ14Sl.mjs} +3 -3
  14. package/dist/agent/chunks/{registry-Bg8kGteS.mjs → registry-D3C_myHO.mjs} +2 -2
  15. package/dist/agent/chunks/{runtime-Bmwgx2hK.mjs → runtime-CImKXCKZ.mjs} +21 -4
  16. package/dist/agent/chunks/{schema-Cwi7iFp2.mjs → schema-CehJcGBp.mjs} +28 -0
  17. package/dist/agent/chunks/{schemaApply-tEIr5lFK.mjs → schemaApply-RJGX9KZk.mjs} +19 -3
  18. package/dist/agent/chunks/{server-3awvGTvL.mjs → server-876r03Db.mjs} +2 -2
  19. package/dist/agent/chunks/{tools-BR3X1Uvm.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-Bp5AxImK.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-Bp5AxImK.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-DyAT9e1o.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-Bp5AxImK.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.7.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-Bmwgx2hK.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-CGIek5YG.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-Bg8kGteS.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-Bu8C87OV.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-Bu8C87OV.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-Bg8kGteS.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-Bg8kGteS.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-Cwi7iFp2.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-Cwi7iFp2.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-Cwi7iFp2.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-Cwi7iFp2.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-Cwi7iFp2.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-Cwi7iFp2.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-Cwi7iFp2.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-Cwi7iFp2.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-tEIr5lFK.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-BR3X1Uvm.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-BR3X1Uvm.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-BR3X1Uvm.mjs");
4028
- const { createMcpServer, serveStdio } = await import("./chunks/server-3awvGTvL.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-CGIek5YG.mjs"),
99
- import("./registry-Bg8kGteS.mjs"),
100
- import("./tools-BR3X1Uvm.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-Bg8kGteS.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-BR3X1Uvm.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-Cwi7iFp2.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-BR3X1Uvm.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-Cwi7iFp2.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-Cwi7iFp2.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-BR3X1Uvm.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";
@@ -8611,7 +8611,8 @@ const FieldContext = reactExports.createContext({
8611
8611
  recordLabel: () => void 0,
8612
8612
  searchRecords: () => [],
8613
8613
  users: [],
8614
- recordHref: (object, id) => `#/objects/${object}/${id}`
8614
+ recordHref: (object, id) => `#/objects/${object}/${id}`,
8615
+ listHref: (object, field, id) => `#/objects/${object}?filter=${encodeURIComponent(`${field}:in:${id}`)}`
8615
8616
  });
8616
8617
  function useFieldContext() {
8617
8618
  return reactExports.useContext(FieldContext);
@@ -10622,7 +10623,23 @@ function RecordAvatar({ recordId, name, size = "md", square, className, imageId
10622
10623
  function stop(e2) {
10623
10624
  e2.stopPropagation();
10624
10625
  }
10625
- function FieldValue({ field, value, compact, className, emptyText = "" }) {
10626
+ function FieldValue(props) {
10627
+ const ctx = useFieldContext();
10628
+ const { field, recordId } = props;
10629
+ if (field.drilldown && recordId && ctx.listHref && !isEmptyFieldValue(field, props.value)) {
10630
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
10631
+ "a",
10632
+ {
10633
+ href: ctx.listHref(field.drilldown.object, field.drilldown.field, recordId),
10634
+ onClick: stop,
10635
+ className: cn("text-primary-600 underline-offset-2 hover:underline dark:text-primary-400", props.className),
10636
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlainFieldValue, { ...props })
10637
+ }
10638
+ );
10639
+ }
10640
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(PlainFieldValue, { ...props });
10641
+ }
10642
+ function PlainFieldValue({ field, value, compact, className, emptyText = "" }) {
10626
10643
  const ctx = useFieldContext();
10627
10644
  if (isEmptyFieldValue(field, value)) return emptyText ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("text-surface-400", className), children: emptyText }) : null;
10628
10645
  const wrap = cn(compact ? "flex min-w-0 items-center gap-1 overflow-hidden" : "flex flex-wrap items-center gap-1", className);
@@ -139,6 +139,30 @@ function dedupeMutations(mutations) {
139
139
  const deleted = new Set(mutations.filter((m) => m.op === "delete").map((m) => `${m.collection}/${m.id}`));
140
140
  return mutations.filter((m) => m.op === "delete" || !deleted.has(`${m.collection}/${m.op === "set" ? m.doc.id : m.id}`));
141
141
  }
142
+ function checkDrilldown(ctx, objectId, d) {
143
+ const target = requireObject(ctx.store, d.object);
144
+ const rel = target.fields.find((f) => f.id === d.field);
145
+ if (!rel || rel.type !== "relation" || rel.relation?.object !== objectId) {
146
+ throw new OpsError("validation", `Drilldown: ${target.labelPlural} has no relation field "${d.field}" pointing at ${objectId}.`);
147
+ }
148
+ return { object: d.object, field: d.field };
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
+ }
142
166
  function buildOptions(input, existing = []) {
143
167
  const out = [];
144
168
  (input ?? []).forEach((o, i) => {
@@ -176,6 +200,8 @@ function buildField(ctx, object, input) {
176
200
  field.relation = { object: rel.object, cardinality: rel.cardinality === "many" ? "many" : "one", ...rel.inverseField ? { inverseField: rel.inverseField } : {} };
177
201
  }
178
202
  if (input.defaultValue !== void 0) field.defaultValue = input.defaultValue;
203
+ if (input.drilldown) field.drilldown = checkDrilldown(ctx, object.id, input.drilldown);
204
+ if (input.rollup) field.rollup = checkRollup(ctx, object.id, input.rollup);
179
205
  return field;
180
206
  }
181
207
  async function createField(ctx, objectId, input) {
@@ -219,6 +245,8 @@ async function updateField(ctx, objectId, fieldId, patch) {
219
245
  }
220
246
  if (patch.currency !== void 0) field.currency = patch.currency.toUpperCase();
221
247
  if (patch.defaultValue !== void 0) field.defaultValue = patch.defaultValue;
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;
222
250
  const mutations = [];
223
251
  let converted;
224
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-Cwi7iFp2.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,6 +50,10 @@ 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 withoutLinks(f) {
54
+ const { drilldown: _drilldown, rollup: _rollup, ...rest } = f;
55
+ return rest;
56
+ }
53
57
  function fieldPatch(field, spec) {
54
58
  const patch = {};
55
59
  const changes = [];
@@ -73,7 +77,7 @@ async function applySchema(ctx, spec) {
73
77
  let current = listObjects(ctx).find((x) => x.id === o.id);
74
78
  const fields = o.fields ?? [];
75
79
  if (!current) {
76
- const plain = fields.filter((f) => f.type !== "relation" && f.id !== "name");
80
+ const plain = fields.filter((f) => f.type !== "relation" && f.id !== "name").map(withoutLinks);
77
81
  current = await createObject(ctx, { id: o.id, labelSingular: o.labelSingular, labelPlural: o.labelPlural, icon: o.icon, color: o.color, fields: plain });
78
82
  report.changes.push({ kind: "object", action: "create", target: o.id, changes: plain.map((f) => f.id) });
79
83
  } else {
@@ -94,7 +98,7 @@ async function applySchema(ctx, spec) {
94
98
  const current2 = listObjects(ctx).find((x) => x.id === o.id);
95
99
  const field = current2.fields.find((x) => x.id === f.id);
96
100
  if (!field) {
97
- await createField(ctx, o.id, f);
101
+ await createField(ctx, o.id, withoutLinks(f));
98
102
  report.changes.push({ kind: "field", action: "create", target: `${o.id}.${f.id}`, changes: [f.type] });
99
103
  continue;
100
104
  }
@@ -120,6 +124,18 @@ async function applySchema(ctx, spec) {
120
124
  const listed = new Set((o.fields ?? []).map((f) => f.id));
121
125
  for (const f of current.fields) if (!f.standard && !f.system && !listed.has(f.id)) report.extraFields.push(`${o.id}.${f.id}`);
122
126
  }
127
+ for (const o of spec.objects ?? []) {
128
+ for (const f of o.fields ?? []) {
129
+ const field = listObjects(ctx).find((x) => x.id === o.id)?.fields.find((x) => x.id === f.id);
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) });
137
+ }
138
+ }
123
139
  for (const p of spec.pipelines ?? []) {
124
140
  const current = listPipelines(ctx).find((x) => x.id === p.id);
125
141
  const stages = p.stages.map((s) => ({ ...s, kind: s.kind ?? "open" }));
@@ -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-BR3X1Uvm.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-Cwi7iFp2.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-Cwi7iFp2.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.7.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.7.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.7.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"