@fleox-agent-crm/agentcrm 0.3.3 → 0.5.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.
- package/README.md +16 -16
- package/changelog.json +22 -0
- package/dist/admin/admin-files.json +7 -7
- package/dist/admin/assets/{chartsImpl-aBuZ1X4W.js → chartsImpl-zjsXDhuy.js} +1 -1
- package/dist/admin/assets/firebase-C3h9mF8O.js +2 -0
- package/dist/admin/assets/{gitJson-DzX3eZ2P.js → gitJson-nrOYgX0x.js} +1 -1
- package/dist/admin/assets/{index-DLy5RpPl.js → index-0ejjkW0z.js} +6 -6
- package/dist/admin/assets/{lucide-react.min-BgcmukkH.js → lucide-react.min-CI5dCsSm.js} +1 -1
- package/dist/admin/assets/{sdk-DtP9zqdi.js → sdk-mepKXtVl.js} +135 -120
- package/dist/admin/index.html +1 -1
- package/dist/agent/agentcrm.mjs +159 -74
- package/dist/agent/chunks/api-BEl_EKwf.mjs +79 -0
- package/dist/agent/chunks/{automations-DwWruxmu.mjs → automations-BqY8EwfJ.mjs} +3 -3
- package/dist/agent/chunks/{backup-W3CjgkAJ.mjs → backup-CO0EzdF_.mjs} +3 -3
- package/dist/agent/chunks/{compact-BGHI92tm.mjs → compact-qF5t42ko.mjs} +3 -3
- package/dist/agent/chunks/{exportCsv-C6e6XEmB.mjs → exportCsv-C-fIHLm1.mjs} +2 -2
- package/dist/agent/chunks/{extCheck-GgHG1dYB.mjs → extCheck-BcbUc7eB.mjs} +4 -4
- package/dist/agent/chunks/{files-D1daDgY0.mjs → files-C4YONVqQ.mjs} +2 -2
- package/dist/agent/chunks/{firebase-DWR0K1OC.mjs → firebase-Bknru2pE.mjs} +230 -53
- package/dist/agent/chunks/firebaseCache-sK4jA0ru.mjs +39 -0
- package/dist/agent/chunks/{firebaseRules-iori-s7U.mjs → firebaseRules-Jq85MBBN.mjs} +14 -3
- package/dist/agent/chunks/{forms-BfuWaQjA.mjs → forms-DJDop3XY.mjs} +2 -2
- package/dist/agent/chunks/{hosting-Dnn1k3cV.mjs → hosting-C_UDyMkm.mjs} +1 -1
- package/dist/agent/chunks/{importCsv-LVmMTaWU.mjs → importCsv-XjQJ9QIR.mjs} +2 -2
- package/dist/agent/chunks/{index-DtCezG4R.mjs → index-DWecFbTi.mjs} +1 -1
- package/dist/agent/chunks/{install-Bp-CwDVC.mjs → install-D1lgtRIH.mjs} +4 -4
- package/dist/agent/chunks/{loader-MPD9iAvh.mjs → loader-Cv0UJf6b.mjs} +11 -11
- package/dist/agent/chunks/{migrate-CsClnnN8.mjs → migrate-Cc_8MHZv.mjs} +1 -1
- package/dist/agent/chunks/{pipelines-BAKpPk1w.mjs → pipelines-DiJ2dLqQ.mjs} +3 -3
- package/dist/agent/chunks/{records-DcHFelq5.mjs → records-CCTxxMWF.mjs} +1 -1
- package/dist/agent/chunks/{registry-COfJrSmg.mjs → registry-ClzNZv9Z.mjs} +10 -10
- package/dist/agent/chunks/{reports-BACHGccj.mjs → reports-WlI_A5Nr.mjs} +3 -3
- package/dist/agent/chunks/{runtime-C0Xf0Axi.mjs → runtime-BAF5vU5D.mjs} +17 -17
- package/dist/agent/chunks/{schema-C4lSslXv.mjs → schema-DOnnH2zL.mjs} +3 -3
- package/dist/agent/chunks/schemaApply-DKHipylx.mjs +164 -0
- package/dist/agent/chunks/{sdk-CYgNyuoK.mjs → sdk-NYUHv7WG.mjs} +493 -214
- package/dist/agent/chunks/{seed-6MRmQQBR.mjs → seed-Bb26Zsni.mjs} +2 -2
- package/dist/agent/chunks/{server-DC3t8r30.mjs → server-Bch4TQon.mjs} +3 -3
- package/dist/agent/chunks/{standardObjects-CheqfDqa.mjs → standardObjects-vrmqIVLH.mjs} +1 -1
- package/dist/agent/chunks/{stats-BfuLWhVV.mjs → stats-DfmDP3tE.mjs} +3 -3
- package/dist/agent/chunks/{tools-iSH-yMpl.mjs → tools-CCk24tdh.mjs} +9 -9
- package/dist/agent/chunks/{views-DH1n9Lrt.mjs → views-BbhmQO3n.mjs} +4 -4
- package/dist/version.json +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/agentcrm-admin/SKILL.md +67 -67
- package/plugin/skills/agentcrm-admin/references/records.md +5 -5
- package/plugin/skills/agentcrm-admin/references/schema.md +19 -19
- package/plugin/skills/agentcrm-extensions/SKILL.md +8 -8
- package/plugin/skills/agentcrm-extensions/references/module-recipes.md +2 -2
- package/plugin/skills/agentcrm-extensions/references/testing.md +14 -14
- package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +3 -3
- package/plugin/skills/agentcrm-install/SKILL.md +13 -13
- package/plugin/skills/agentcrm-install/references/firebase.md +1 -1
- package/plugin/skills/agentcrm-install/references/github.md +1 -1
- package/plugin/skills/agentcrm-install/references/mcp.md +2 -2
- package/plugin/skills/agentcrm-install/references/plans.md +1 -1
- package/plugin/skills/agentcrm-install/references/s3.md +1 -1
- package/plugin/skills/agentcrm-manage/SKILL.md +15 -15
- package/plugin/skills/agentcrm-sales/SKILL.md +18 -18
- package/dist/admin/assets/firebase-BG1GpyBB.js +0 -2
- package/dist/agent/chunks/api-Dwb4xz1k.mjs +0 -27
package/dist/agent/agentcrm.mjs
CHANGED
|
@@ -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.
|
|
145
|
+
const version = "0.5.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-
|
|
527
|
+
await import("./chunks/runtime-BAF5vU5D.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-
|
|
542
|
+
const { syncExtensions } = await import("./chunks/loader-Cv0UJf6b.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-
|
|
556
|
+
(await import("./chunks/registry-ClzNZv9Z.mjs")).deactivateAllExtensions();
|
|
557
557
|
}
|
|
558
558
|
};
|
|
559
559
|
}
|
|
@@ -608,7 +608,7 @@ async function openStore(runtime, opts) {
|
|
|
608
608
|
}
|
|
609
609
|
if (runtime.backend === "journal") {
|
|
610
610
|
if (!opts.dataTarget) throw new CliError("internal", "journal store without a data location");
|
|
611
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
611
|
+
const { buildConnector } = await import("./chunks/hosting-C_UDyMkm.mjs");
|
|
612
612
|
const { createJournalStore } = await import("./chunks/index-B-4W0-P4.mjs");
|
|
613
613
|
const { publicSettings, secrets } = rc.splitSecretSettings(opts.dataTarget.settings);
|
|
614
614
|
rc.setConnectorSecrets(runtime, secrets);
|
|
@@ -629,8 +629,9 @@ async function openStore(runtime, opts) {
|
|
|
629
629
|
const { prepareFirebaseSession: prepareFirebaseSession2 } = await Promise.resolve().then(() => firebaseSession);
|
|
630
630
|
await prepareFirebaseSession2(opts.account, runtime.firebase, opts.secrets.email);
|
|
631
631
|
}
|
|
632
|
-
const { createDataStore } = await import("./chunks/index-
|
|
633
|
-
|
|
632
|
+
const { createDataStore } = await import("./chunks/index-DWecFbTi.mjs");
|
|
633
|
+
const firebaseCache = runtime.backend === "firebase" ? (await import("./chunks/firebaseCache-sK4jA0ru.mjs")).fileFirebaseCache() : void 0;
|
|
634
|
+
return createDataStore(runtime, { secrets: opts.secrets ?? {}, passphrase: opts.passphrase ?? null, clientId: cliClientId(), firebaseCache });
|
|
634
635
|
}
|
|
635
636
|
function siteSecrets(site) {
|
|
636
637
|
const passphrase = site.credentials.passphrase ? requireCredential(site.credentials.passphrase).values.passphrase : null;
|
|
@@ -680,7 +681,7 @@ async function openSession(alias, opts = {}) {
|
|
|
680
681
|
const [{ createOpsContext }, { createPluginRegistry, plugins: defaultPlugins }, { installAutomations }] = await Promise.all([
|
|
681
682
|
import("./chunks/context-CxFfqS4D.mjs"),
|
|
682
683
|
import("./chunks/pluginRegistry-DyHtlkcr.mjs"),
|
|
683
|
-
import("./chunks/automations-
|
|
684
|
+
import("./chunks/automations-BqY8EwfJ.mjs")
|
|
684
685
|
]);
|
|
685
686
|
const own = createPluginRegistry((hook, err) => process.stderr.write(`[agentcrm] ${hook} handler failed: ${String(err?.message ?? err)}
|
|
686
687
|
`));
|
|
@@ -694,7 +695,7 @@ async function openSession(alias, opts = {}) {
|
|
|
694
695
|
const ctx = createOpsContext(store, user, { plugins, log });
|
|
695
696
|
const system = createOpsContext(store, null, { plugins, log });
|
|
696
697
|
if (opts.lock && (!user || user.role === "admin") && store.list("objects").length) {
|
|
697
|
-
const { migrateSchema } = await import("./chunks/migrate-
|
|
698
|
+
const { migrateSchema } = await import("./chunks/migrate-Cc_8MHZv.mjs").then((n) => n.c);
|
|
698
699
|
await migrateSchema(ctx).catch((err) => warnings.push(`Schema migration skipped: ${err.message}`));
|
|
699
700
|
}
|
|
700
701
|
if (site.hosting) {
|
|
@@ -707,14 +708,14 @@ async function openSession(alias, opts = {}) {
|
|
|
707
708
|
})();
|
|
708
709
|
if (target) {
|
|
709
710
|
const { setStorageConfigSource, registerStorageConnector } = await import("./chunks/registry-DijAKZ24.mjs").then((n) => n.r);
|
|
710
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
711
|
+
const { buildConnector } = await import("./chunks/hosting-C_UDyMkm.mjs");
|
|
711
712
|
if (target.connectorId === "local-folder") registerStorageConnector({ id: "local-folder", create: (s) => buildConnector({ connectorId: "local-folder", settings: s }) });
|
|
712
713
|
setStorageConfigSource(async () => target);
|
|
713
714
|
}
|
|
714
715
|
}
|
|
715
716
|
{
|
|
716
|
-
const forms = await import("./chunks/forms-
|
|
717
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
717
|
+
const forms = await import("./chunks/forms-DJDop3XY.mjs");
|
|
718
|
+
const { buildConnector } = await import("./chunks/hosting-C_UDyMkm.mjs");
|
|
718
719
|
forms.setInboxSourceResolver((_ctx, form) => {
|
|
719
720
|
if (form.inbox.kind !== "s3") return null;
|
|
720
721
|
const settings = form.inbox.settings ?? {};
|
|
@@ -913,6 +914,29 @@ function table(rows, columns) {
|
|
|
913
914
|
const SITE_OPTION = { name: "site", type: "string", description: "Site alias (default: $AGENTCRM_SITE, ./agentcrm.json, the only site, or `site use`)." };
|
|
914
915
|
const AS_OPTION = { name: "as", type: "string", description: "Act as this CRM user (email or id) instead of the site's user." };
|
|
915
916
|
const YES_OPTION = { name: "yes", type: "boolean", description: "Apply — only after the user confirmed the plan." };
|
|
917
|
+
const util = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
918
|
+
__proto__: null,
|
|
919
|
+
AS_OPTION,
|
|
920
|
+
SITE_OPTION,
|
|
921
|
+
YES_OPTION,
|
|
922
|
+
boolOpt,
|
|
923
|
+
fieldsInput,
|
|
924
|
+
jsonObjectOpt,
|
|
925
|
+
jsonOpt,
|
|
926
|
+
listOpt,
|
|
927
|
+
multiOpt,
|
|
928
|
+
numOpt,
|
|
929
|
+
parseFilters,
|
|
930
|
+
parseScalar,
|
|
931
|
+
parseSorts,
|
|
932
|
+
positional,
|
|
933
|
+
readTextValue,
|
|
934
|
+
requireStr,
|
|
935
|
+
strOpt,
|
|
936
|
+
table,
|
|
937
|
+
usage,
|
|
938
|
+
writeOutFile
|
|
939
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
916
940
|
function fileOut(f) {
|
|
917
941
|
return {
|
|
918
942
|
id: f.id,
|
|
@@ -935,7 +959,7 @@ function readLocalFile(path) {
|
|
|
935
959
|
return { name: basename(full), bytes: new Uint8Array(readFileSync(full)) };
|
|
936
960
|
}
|
|
937
961
|
async function uploadLocalFiles(ctx, paths, targets2 = []) {
|
|
938
|
-
const { uploadFile } = await import("./chunks/files-
|
|
962
|
+
const { uploadFile } = await import("./chunks/files-C4YONVqQ.mjs");
|
|
939
963
|
const { guessMime, imageDimensions } = await import("./chunks/files-CjsPJSR6.mjs");
|
|
940
964
|
const out = [];
|
|
941
965
|
for (const p of paths) {
|
|
@@ -983,7 +1007,7 @@ const filesCommand = {
|
|
|
983
1007
|
switch (action) {
|
|
984
1008
|
case "list":
|
|
985
1009
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
986
|
-
const { listFiles } = await import("./chunks/files-
|
|
1010
|
+
const { listFiles } = await import("./chunks/files-C4YONVqQ.mjs");
|
|
987
1011
|
const target = strOpt(options, "record") ?? strOpt(options, "activity") ?? null;
|
|
988
1012
|
const items = listFiles(ctx, target, { includeRelated: boolOpt(options, "related"), kind: strOpt(options, "kind"), search: strOpt(options, "search") });
|
|
989
1013
|
const limit = Math.min(1e3, numOpt(options, "limit") ?? 100);
|
|
@@ -998,7 +1022,7 @@ ${table(r.files, ["id", "name", "mime", "size", "createdAt"])}`);
|
|
|
998
1022
|
if (record && activity) usage("Give --record or --activity, not both.");
|
|
999
1023
|
for (const p of args) readLocalFile(p);
|
|
1000
1024
|
return withSession(io, options, { lock: true }, async ({ ctx }) => {
|
|
1001
|
-
const { attachFile } = await import("./chunks/files-
|
|
1025
|
+
const { attachFile } = await import("./chunks/files-C4YONVqQ.mjs");
|
|
1002
1026
|
const files2 = await uploadLocalFiles(ctx, args, record ? [record] : []);
|
|
1003
1027
|
if (activity) for (const f of files2) await attachFile(ctx, f.id, { kind: "activity", id: activity });
|
|
1004
1028
|
const { requireFile } = await import("./chunks/store-5gqRSKXg.mjs");
|
|
@@ -1011,7 +1035,7 @@ ${table(r.uploaded, ["id", "name", "size"])}`);
|
|
|
1011
1035
|
const out = strOpt(options, "out");
|
|
1012
1036
|
if (!out) usage("files get needs --out <path>.");
|
|
1013
1037
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
1014
|
-
const { getFile, getFileBytes } = await import("./chunks/files-
|
|
1038
|
+
const { getFile, getFileBytes } = await import("./chunks/files-C4YONVqQ.mjs");
|
|
1015
1039
|
const meta = getFile(ctx, id);
|
|
1016
1040
|
const bytes = await getFileBytes(ctx, id, { thumb: boolOpt(options, "thumb") });
|
|
1017
1041
|
writeOutFile(out, bytes);
|
|
@@ -1021,7 +1045,7 @@ ${table(r.uploaded, ["id", "name", "size"])}`);
|
|
|
1021
1045
|
case "delete": {
|
|
1022
1046
|
const id = positional(args, 0, "file id", U$1.delete);
|
|
1023
1047
|
return withSession(io, options, { lock: options.yes === true }, async ({ ctx }) => {
|
|
1024
|
-
const { getFile, deleteFile } = await import("./chunks/files-
|
|
1048
|
+
const { getFile, deleteFile } = await import("./chunks/files-C4YONVqQ.mjs");
|
|
1025
1049
|
const meta = fileOut(getFile(ctx, id));
|
|
1026
1050
|
if (options.yes !== true) return { needsConfirmation: true, plan: { delete: meta } };
|
|
1027
1051
|
await deleteFile(ctx, id);
|
|
@@ -1029,7 +1053,7 @@ ${table(r.uploaded, ["id", "name", "size"])}`);
|
|
|
1029
1053
|
}, (r) => "plan" in r && r.plan ? `Would delete ${r.plan.delete.name} (${r.plan.delete.id}). Re-run with --yes once the user agrees.` : `Deleted ${"deleted" in r ? r.deleted : id} (bytes purged by \`agentcrm compact\`).`);
|
|
1030
1054
|
}
|
|
1031
1055
|
case "usage":
|
|
1032
|
-
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/files-
|
|
1056
|
+
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/files-C4YONVqQ.mjs")).fileUsage(ctx));
|
|
1033
1057
|
default:
|
|
1034
1058
|
usage(`Unknown files action "${action ?? ""}".`, "Use list, upload, get, delete or usage.");
|
|
1035
1059
|
}
|
|
@@ -1042,7 +1066,7 @@ async function recordImageAction(io, options, args) {
|
|
|
1042
1066
|
if (!remove && !path) usage("records image needs an image path (or --remove).");
|
|
1043
1067
|
const local = remove ? null : readLocalFile(path);
|
|
1044
1068
|
return withSession(io, options, { lock: true }, async ({ ctx }) => {
|
|
1045
|
-
const { setRecordImage, clearRecordImage } = await import("./chunks/files-
|
|
1069
|
+
const { setRecordImage, clearRecordImage } = await import("./chunks/files-C4YONVqQ.mjs");
|
|
1046
1070
|
const field = strOpt(options, "field");
|
|
1047
1071
|
if (!local) {
|
|
1048
1072
|
const r = await clearRecordImage(ctx, recordId, field);
|
|
@@ -1330,7 +1354,7 @@ const recordsCommand = {
|
|
|
1330
1354
|
const filters = parseFilters(multiOpt(options, "filter"), FILTER_OPS);
|
|
1331
1355
|
const sorts = parseSorts(multiOpt(options, "sort"));
|
|
1332
1356
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
1333
|
-
const { listRecords } = await import("./chunks/records-
|
|
1357
|
+
const { listRecords } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1334
1358
|
const page = listRecords(ctx, objectId, {
|
|
1335
1359
|
filters,
|
|
1336
1360
|
sorts,
|
|
@@ -1348,7 +1372,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1348
1372
|
case "get": {
|
|
1349
1373
|
const id = positional(args, 0, "record id", U.get);
|
|
1350
1374
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
1351
|
-
const { getRecordDetails } = await import("./chunks/records-
|
|
1375
|
+
const { getRecordDetails } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1352
1376
|
const d = getRecordDetails(ctx, id);
|
|
1353
1377
|
return { ...await recordOut(ctx, d.record), relations: d.relations, related: d.inverse.filter((i) => i.records.length), activityCount: d.activityCount };
|
|
1354
1378
|
});
|
|
@@ -1359,7 +1383,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1359
1383
|
if (!Object.keys(fields).length) usage("records create needs --fields or --set.", `Usage: agentcrm ${U.create}`);
|
|
1360
1384
|
const owner = strOpt(options, "owner");
|
|
1361
1385
|
return withSession(io, options, { lock: true }, async ({ ctx }) => {
|
|
1362
|
-
const { createRecord } = await import("./chunks/records-
|
|
1386
|
+
const { createRecord } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1363
1387
|
return recordOut(ctx, await createRecord(ctx, objectId, fields, owner ? { ownerId: owner } : {}));
|
|
1364
1388
|
}, (r) => `Created ${r.object} ${r.id} (${String(r.label)})`);
|
|
1365
1389
|
}
|
|
@@ -1369,7 +1393,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1369
1393
|
const owner = strOpt(options, "owner");
|
|
1370
1394
|
if (!Object.keys(fields).length && owner === void 0) usage("records update needs --fields, --set or --owner.");
|
|
1371
1395
|
return withSession(io, options, { lock: true }, async ({ ctx }) => {
|
|
1372
|
-
const { updateRecord } = await import("./chunks/records-
|
|
1396
|
+
const { updateRecord } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1373
1397
|
return recordOut(ctx, await updateRecord(ctx, id, fields, owner !== void 0 ? { ownerId: owner || null } : {}));
|
|
1374
1398
|
}, (r) => `Updated ${r.id} (${String(r.label)})`);
|
|
1375
1399
|
}
|
|
@@ -1377,7 +1401,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1377
1401
|
if (!args.length) usage("records delete needs at least one id.", `Usage: agentcrm ${U.delete}`);
|
|
1378
1402
|
const hard = boolOpt(options, "hard");
|
|
1379
1403
|
return withSession(io, options, { lock: options.yes === true }, async ({ ctx }) => {
|
|
1380
|
-
const { getRecord, deleteRecord, bulkDelete } = await import("./chunks/records-
|
|
1404
|
+
const { getRecord, deleteRecord, bulkDelete } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1381
1405
|
const { recordLabel } = await import("./chunks/fields-B0bitgmr.mjs");
|
|
1382
1406
|
const { objectOf } = await import("./chunks/store-5gqRSKXg.mjs");
|
|
1383
1407
|
const targets2 = args.map((id) => getRecord(ctx, id, { includeDeleted: true }));
|
|
@@ -1390,7 +1414,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1390
1414
|
case "restore": {
|
|
1391
1415
|
const id = positional(args, 0, "record id", U.restore);
|
|
1392
1416
|
return withSession(io, options, { lock: true }, async ({ ctx }) => {
|
|
1393
|
-
const { restoreRecord } = await import("./chunks/records-
|
|
1417
|
+
const { restoreRecord } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1394
1418
|
return recordOut(ctx, await restoreRecord(ctx, id));
|
|
1395
1419
|
});
|
|
1396
1420
|
}
|
|
@@ -1398,7 +1422,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1398
1422
|
const query = args.join(" ").trim();
|
|
1399
1423
|
if (!query) usage("records search needs a query.", `Usage: agentcrm ${U.search}`);
|
|
1400
1424
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
1401
|
-
const { searchRecords } = await import("./chunks/records-
|
|
1425
|
+
const { searchRecords } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1402
1426
|
return searchRecords(ctx, query, { objects: listOpt(options, "object"), limit: Math.min(100, numOpt(options, "limit") ?? 20) });
|
|
1403
1427
|
});
|
|
1404
1428
|
}
|
|
@@ -1415,7 +1439,7 @@ ${table(r.records, ["id", "label", "updatedAt"])}`);
|
|
|
1415
1439
|
const [primary, ...dups] = args;
|
|
1416
1440
|
if (!primary || !dups.length) usage("records merge needs <primaryId> <duplicateId>….", `Usage: agentcrm ${U.merge}`);
|
|
1417
1441
|
return withSession(io, options, { lock: options.yes === true }, async ({ ctx }) => {
|
|
1418
|
-
const { getRecord } = await import("./chunks/records-
|
|
1442
|
+
const { getRecord } = await import("./chunks/records-CCTxxMWF.mjs");
|
|
1419
1443
|
const all = [primary, ...dups].map((id) => getRecord(ctx, id));
|
|
1420
1444
|
const plan = { primary: await recordOut(ctx, all[0]), duplicates: await Promise.all(all.slice(1).map((r) => recordOut(ctx, r))) };
|
|
1421
1445
|
if (options.yes !== true) return { needsConfirmation: true, plan };
|
|
@@ -1447,13 +1471,13 @@ const pipelinesCommand = {
|
|
|
1447
1471
|
io,
|
|
1448
1472
|
options,
|
|
1449
1473
|
{},
|
|
1450
|
-
async ({ ctx }) => (await import("./chunks/pipelines-
|
|
1474
|
+
async ({ ctx }) => (await import("./chunks/pipelines-DiJ2dLqQ.mjs")).listPipelines(ctx, strOpt(options, "object")),
|
|
1451
1475
|
(ps) => ps.map((p) => `${p.id} (${p.name}, ${p.object}): ${p.stages.map((s) => `${s.label} ${Math.round(s.probability * (s.probability <= 1 ? 100 : 1))}%`).join(" → ")}`).join("\n")
|
|
1452
1476
|
);
|
|
1453
1477
|
}
|
|
1454
1478
|
if (action === "move") {
|
|
1455
1479
|
if (!id || !stage.length) usage("pipelines move needs <recordId> <stage>.");
|
|
1456
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => recordOut(ctx, await (await import("./chunks/pipelines-
|
|
1480
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => recordOut(ctx, await (await import("./chunks/pipelines-DiJ2dLqQ.mjs")).moveStage(ctx, id, stage.join(" "), { lostReason: strOpt(options, "lost-reason") })));
|
|
1457
1481
|
}
|
|
1458
1482
|
usage(`Unknown pipelines action "${action}".`, "Use list or move.");
|
|
1459
1483
|
}
|
|
@@ -1485,7 +1509,7 @@ const viewsCommand = {
|
|
|
1485
1509
|
const [action = "list", id] = positionals;
|
|
1486
1510
|
switch (action) {
|
|
1487
1511
|
case "list":
|
|
1488
|
-
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/views-
|
|
1512
|
+
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/views-BbhmQO3n.mjs")).listViews(ctx, strOpt(options, "object")), (vs) => table(vs, ["id", "object", "name", "type", "shared"]));
|
|
1489
1513
|
case "create": {
|
|
1490
1514
|
const type2 = strOpt(options, "type") ?? "table";
|
|
1491
1515
|
if (type2 !== "table" && type2 !== "kanban") usage("--type must be table or kanban.");
|
|
@@ -1500,12 +1524,12 @@ const viewsCommand = {
|
|
|
1500
1524
|
...strOpt(options, "pipeline") ? { pipelineId: strOpt(options, "pipeline") } : {},
|
|
1501
1525
|
shared: boolOpt(options, "shared")
|
|
1502
1526
|
};
|
|
1503
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/views-
|
|
1527
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/views-BbhmQO3n.mjs")).createView(ctx, input));
|
|
1504
1528
|
}
|
|
1505
1529
|
case "delete":
|
|
1506
1530
|
if (!id) usage("views delete needs a view id.");
|
|
1507
1531
|
return withSession(io, options, { lock: options.yes === true }, async ({ ctx }) => {
|
|
1508
|
-
const { getView, deleteView } = await import("./chunks/views-
|
|
1532
|
+
const { getView, deleteView } = await import("./chunks/views-BbhmQO3n.mjs");
|
|
1509
1533
|
const v = getView(ctx, id);
|
|
1510
1534
|
if (options.yes !== true) return { needsConfirmation: true, plan: { delete: { id: v.id, name: v.name, object: v.object, shared: v.shared } } };
|
|
1511
1535
|
return deleteView(ctx, id);
|
|
@@ -1713,7 +1737,7 @@ function filePersistence(account, email) {
|
|
|
1713
1737
|
};
|
|
1714
1738
|
}
|
|
1715
1739
|
async function prepareFirebaseSession(account, options, email) {
|
|
1716
|
-
const { getFirebaseApp } = await import("./chunks/sdk-
|
|
1740
|
+
const { getFirebaseApp } = await import("./chunks/sdk-NYUHv7WG.mjs");
|
|
1717
1741
|
const { initializeAuth } = await import("./chunks/index-Dio0aBWA.mjs").then((n) => n.x);
|
|
1718
1742
|
try {
|
|
1719
1743
|
initializeAuth(getFirebaseApp(options), { persistence: filePersistence(account, email.trim().toLowerCase()) });
|
|
@@ -1832,6 +1856,10 @@ async function dryRun(ctx, work) {
|
|
|
1832
1856
|
const copy = createOpsContext(store, ctx.user, { now: ctx.now, plugins: createPluginRegistry(() => void 0) });
|
|
1833
1857
|
return { result: await work(copy), store };
|
|
1834
1858
|
}
|
|
1859
|
+
const dryRun$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1860
|
+
__proto__: null,
|
|
1861
|
+
dryRun
|
|
1862
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1835
1863
|
const CASCADE_OPTION = { name: "cascade", type: "boolean", description: "enable / disable: also enable the dependencies / disable the dependents." };
|
|
1836
1864
|
function parseJsonValue(raw, name2) {
|
|
1837
1865
|
const text = readTextValue(raw, name2);
|
|
@@ -2096,7 +2124,7 @@ async function check({ io, options, positionals }) {
|
|
|
2096
2124
|
const kind = strOpt(options, "kind");
|
|
2097
2125
|
if (kind && kind !== "module" && kind !== "theme") usage("--kind is module or theme.");
|
|
2098
2126
|
const { readRawPackage } = await import("./chunks/extPackage-DuZ6GZhp.mjs");
|
|
2099
|
-
const { checkExtension } = await import("./chunks/extCheck-
|
|
2127
|
+
const { checkExtension } = await import("./chunks/extCheck-BcbUc7eB.mjs");
|
|
2100
2128
|
const raw = await readRawPackage(target);
|
|
2101
2129
|
const report = await checkExtension(raw, { kind, callTools: !boolOpt(options, "no-call") });
|
|
2102
2130
|
printResult(io, report, () => {
|
|
@@ -2143,7 +2171,7 @@ async function install({ io, options, positionals }) {
|
|
|
2143
2171
|
const apply = options.yes === true;
|
|
2144
2172
|
const disabled = boolOpt(options, "disabled");
|
|
2145
2173
|
if (!boolOpt(options, "force")) {
|
|
2146
|
-
const { checkExtension } = await import("./chunks/extCheck-
|
|
2174
|
+
const { checkExtension } = await import("./chunks/extCheck-BcbUc7eB.mjs");
|
|
2147
2175
|
const report = await checkExtension(raw, { callTools: false });
|
|
2148
2176
|
if (!report.valid) {
|
|
2149
2177
|
throw new CliError(
|
|
@@ -2179,7 +2207,7 @@ async function install({ io, options, positionals }) {
|
|
|
2179
2207
|
}
|
|
2180
2208
|
const result = await ext.installExtension(s.ctx, pkg2, disabled ? { enabled: false } : {});
|
|
2181
2209
|
const report = await s.extensions.sync();
|
|
2182
|
-
const { getLoadedExtension } = await import("./chunks/registry-
|
|
2210
|
+
const { getLoadedExtension } = await import("./chunks/registry-ClzNZv9Z.mjs");
|
|
2183
2211
|
const loaded = getLoadedExtension(m.id);
|
|
2184
2212
|
const failure = report?.failed.find((f) => f.id === m.id || f.id === "*");
|
|
2185
2213
|
if (failure && !loaded) return { ...result, author: m.author ?? null, load: { status: "error", error: failure.error } };
|
|
@@ -2241,7 +2269,7 @@ const extCommand = {
|
|
|
2241
2269
|
if (kind && kind !== "module" && kind !== "theme") usage("--kind is module or theme.");
|
|
2242
2270
|
return withSession(io, options, {}, async (s) => {
|
|
2243
2271
|
const { listExtensions } = await import("./chunks/extensions-Bp72uZ9a.mjs");
|
|
2244
|
-
const { getLoadedExtension } = await import("./chunks/registry-
|
|
2272
|
+
const { getLoadedExtension } = await import("./chunks/registry-ClzNZv9Z.mjs");
|
|
2245
2273
|
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 } : {} }));
|
|
2246
2274
|
}, (rows) => table(rows.map((r) => ({ ...r, enabled: r.enabled ? "yes" : "no" })), ["id", "kind", "name", "version", "enabled", "load", "author"]));
|
|
2247
2275
|
}
|
|
@@ -2356,7 +2384,7 @@ const importCommand = {
|
|
|
2356
2384
|
options,
|
|
2357
2385
|
{},
|
|
2358
2386
|
async ({ ctx }) => {
|
|
2359
|
-
const plan = await (await import("./chunks/backup-
|
|
2387
|
+
const plan = await (await import("./chunks/backup-CO0EzdF_.mjs")).planBackupZip(ctx, bytes, { mode: options.replace === true ? "replace" : "merge" });
|
|
2360
2388
|
return { needsConfirmation: true, plan: { restore: resolve(path), bytes: bytes.length, ...plan } };
|
|
2361
2389
|
},
|
|
2362
2390
|
(r) => [
|
|
@@ -2366,7 +2394,7 @@ const importCommand = {
|
|
|
2366
2394
|
].join("\n")
|
|
2367
2395
|
);
|
|
2368
2396
|
}
|
|
2369
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/backup-
|
|
2397
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/backup-CO0EzdF_.mjs")).importBackupZip(ctx, bytes, { mode: options.replace === true ? "replace" : "merge" }), (r) => `Restored ${r.written} document(s) and ${r.files} file(s)`);
|
|
2370
2398
|
}
|
|
2371
2399
|
if (kind !== "csv") usage('Only "import csv" and "import zip" are supported.', "Usage: agentcrm import csv <file> --object <id>");
|
|
2372
2400
|
const source = positional(positionals, 1, "CSV file (or -)", "import csv <file|-> --object <id>");
|
|
@@ -2377,7 +2405,7 @@ const importCommand = {
|
|
|
2377
2405
|
const apply = options.yes === true && options["dry-run"] !== true;
|
|
2378
2406
|
const shown = numOpt(options, "rows") ?? 100;
|
|
2379
2407
|
return withSession(io, options, { lock: apply }, async ({ ctx }) => {
|
|
2380
|
-
const { importCsv } = await import("./chunks/importCsv-
|
|
2408
|
+
const { importCsv } = await import("./chunks/importCsv-XjQJ9QIR.mjs");
|
|
2381
2409
|
const report = await importCsv(ctx, {
|
|
2382
2410
|
object: objectId,
|
|
2383
2411
|
csv,
|
|
@@ -2426,7 +2454,7 @@ const exportCommand = {
|
|
|
2426
2454
|
const file2 = strOpt(options, "out");
|
|
2427
2455
|
if (!file2) usage("export zip needs --out <file.zip>.");
|
|
2428
2456
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
2429
|
-
const { exportBackupZip } = await import("./chunks/backup-
|
|
2457
|
+
const { exportBackupZip } = await import("./chunks/backup-CO0EzdF_.mjs");
|
|
2430
2458
|
const { zip, report } = await exportBackupZip(ctx, { includeFiles: options["no-files"] !== true });
|
|
2431
2459
|
writeOutFile(file2, zip);
|
|
2432
2460
|
return { file: resolve(file2), zipBytes: zip.length, files: report.files, missing: report.missing, fileBytes: report.bytes };
|
|
@@ -2445,7 +2473,7 @@ const exportCommand = {
|
|
|
2445
2473
|
const filters = parseFilters(multiOpt(options, "filter"), FILTER_OPS);
|
|
2446
2474
|
const sorts = parseSorts(multiOpt(options, "sort"));
|
|
2447
2475
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
2448
|
-
const { exportCsv } = await import("./chunks/exportCsv-
|
|
2476
|
+
const { exportCsv } = await import("./chunks/exportCsv-C-fIHLm1.mjs");
|
|
2449
2477
|
const csv = exportCsv(ctx, objectId, {
|
|
2450
2478
|
viewId: strOpt(options, "view"),
|
|
2451
2479
|
filters,
|
|
@@ -2461,7 +2489,7 @@ const exportCommand = {
|
|
|
2461
2489
|
}
|
|
2462
2490
|
if (kind === "json") {
|
|
2463
2491
|
return withSession(io, options, {}, async ({ ctx }) => {
|
|
2464
|
-
const { exportJson } = await import("./chunks/exportCsv-
|
|
2492
|
+
const { exportJson } = await import("./chunks/exportCsv-C-fIHLm1.mjs");
|
|
2465
2493
|
const data = exportJson(ctx, { collections: listOpt(options, "collections") });
|
|
2466
2494
|
const text = JSON.stringify(data, null, 2);
|
|
2467
2495
|
if (out) return deliver(text, {});
|
|
@@ -2505,7 +2533,7 @@ const reportCommand = {
|
|
|
2505
2533
|
...strOpt(options, "pipeline") ? { pipelineId: strOpt(options, "pipeline") } : {},
|
|
2506
2534
|
...strOpt(options, "owner") ? { ownerId: strOpt(options, "owner") } : {}
|
|
2507
2535
|
};
|
|
2508
|
-
return withSession(io, options, {}, async ({ ctx }) => ({ report: name2, data: (await import("./chunks/reports-
|
|
2536
|
+
return withSession(io, options, {}, async ({ ctx }) => ({ report: name2, data: (await import("./chunks/reports-WlI_A5Nr.mjs")).runReport(ctx, internal, params) }));
|
|
2509
2537
|
}
|
|
2510
2538
|
};
|
|
2511
2539
|
const statsCommand = {
|
|
@@ -2515,7 +2543,7 @@ const statsCommand = {
|
|
|
2515
2543
|
options: [SITE_OPTION, AS_OPTION],
|
|
2516
2544
|
async run({ io, options }) {
|
|
2517
2545
|
return withSession(io, options, {}, async ({ ctx, store }) => {
|
|
2518
|
-
const stats = (await import("./chunks/stats-
|
|
2546
|
+
const stats = (await import("./chunks/stats-DfmDP3tE.mjs")).getStats(ctx);
|
|
2519
2547
|
const journal = store.stats;
|
|
2520
2548
|
return { ...stats, ...journal ? { journal: await journal.call(store) } : {} };
|
|
2521
2549
|
}, (s) => [`backend: ${s.backend}`, ...s.objects.map((o) => ` ${o.label}: ${o.count}${o.deleted ? ` (+${o.deleted} deleted)` : ""}`), `open tasks: ${s.openTasks} (${s.overdueTasks} overdue)`, `users: ${s.users}`].join("\n"));
|
|
@@ -2529,7 +2557,7 @@ const compactCommand = {
|
|
|
2529
2557
|
async run({ io, options }) {
|
|
2530
2558
|
const apply = options.yes === true;
|
|
2531
2559
|
return withSession(io, options, { lock: apply }, async ({ ctx }) => {
|
|
2532
|
-
const { compactData } = await import("./chunks/compact-
|
|
2560
|
+
const { compactData } = await import("./chunks/compact-qF5t42ko.mjs");
|
|
2533
2561
|
const report = await compactData(ctx, { olderThanDays: numOpt(options, "older-than"), keepRuns: numOpt(options, "keep-runs"), dryRun: !apply });
|
|
2534
2562
|
return apply ? report : { needsConfirmation: true, plan: report };
|
|
2535
2563
|
}, (r) => "plan" in r ? `Would purge ${r.plan.purgedRecords.length} record(s), ${r.plan.purgedActivities} activit(ies), ${r.plan.purgedRuns} run(s), ${r.plan.purgedFiles} file(s). Re-run with --yes once the user agrees.` : `Purged ${r.purgedRecords.length} record(s), ${r.purgedFiles} file(s); storage compacted: ${r.storageCompacted}`);
|
|
@@ -2550,19 +2578,19 @@ const automationsCommand = {
|
|
|
2550
2578
|
const [action = "list", id] = positionals;
|
|
2551
2579
|
switch (action) {
|
|
2552
2580
|
case "list":
|
|
2553
|
-
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/automations-
|
|
2581
|
+
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/automations-BqY8EwfJ.mjs")).listAutomations(ctx).map((a) => ({ id: a.id, name: a.name, enabled: a.enabled, object: a.object, trigger: a.trigger, actions: a.actions.map((x) => x.type), lastRunAt: a.lastRunAt ? new Date(a.lastRunAt).toISOString() : null })), (rows) => table(rows, ["id", "name", "enabled", "object", "lastRunAt"]));
|
|
2554
2582
|
case "enable":
|
|
2555
2583
|
case "disable": {
|
|
2556
2584
|
if (!id) usage(`automations ${action} needs an id.`);
|
|
2557
2585
|
return withSession(io, options, { lock: true }, async ({ ctx }) => {
|
|
2558
|
-
const mod = await import("./chunks/automations-
|
|
2586
|
+
const mod = await import("./chunks/automations-BqY8EwfJ.mjs");
|
|
2559
2587
|
return mod.setAutomationEnabled(ctx, id, action === "enable");
|
|
2560
2588
|
});
|
|
2561
2589
|
}
|
|
2562
2590
|
case "run": {
|
|
2563
2591
|
const apply = options.yes === true;
|
|
2564
2592
|
return withSession(io, options, { lock: apply }, async ({ ctx }) => {
|
|
2565
|
-
const { runScheduled } = await import("./chunks/automations-
|
|
2593
|
+
const { runScheduled } = await import("./chunks/automations-BqY8EwfJ.mjs");
|
|
2566
2594
|
const report = await runScheduled(ctx, { dryRun: !apply, automationId: strOpt(options, "id"), force: boolOpt(options, "force") });
|
|
2567
2595
|
return apply ? report : { needsConfirmation: true, ...report };
|
|
2568
2596
|
}, (r) => `${"needsConfirmation" in r ? "DRY RUN — " : ""}ran ${r.ran}, skipped ${r.skipped}, errors ${r.errors}`);
|
|
@@ -2586,16 +2614,16 @@ const formsCommand = {
|
|
|
2586
2614
|
const [action = "list", id] = positionals;
|
|
2587
2615
|
switch (action) {
|
|
2588
2616
|
case "list":
|
|
2589
|
-
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/forms-
|
|
2617
|
+
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/forms-DJDop3XY.mjs")).listForms(ctx), (fs) => table(fs, ["id", "name", "object", "publishedPath"]));
|
|
2590
2618
|
case "publish": {
|
|
2591
2619
|
if (!id) usage("forms publish needs a form id.");
|
|
2592
2620
|
return withSession(io, options, { lock: options.yes === true }, async (s) => {
|
|
2593
|
-
const forms = await import("./chunks/forms-
|
|
2621
|
+
const forms = await import("./chunks/forms-DJDop3XY.mjs");
|
|
2594
2622
|
const built = await forms.buildFormHtml(s.ctx, id);
|
|
2595
2623
|
const target = s.hostingTarget();
|
|
2596
2624
|
if (!target) usage(`${s.site.alias} has no hosting to publish the form to.`);
|
|
2597
2625
|
if (options.yes !== true) return { needsConfirmation: true, plan: { form: id, path: built.path, hosting: s.site.hosting?.type, bytes: built.html.length } };
|
|
2598
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
2626
|
+
const { buildConnector } = await import("./chunks/hosting-C_UDyMkm.mjs");
|
|
2599
2627
|
const connector = buildConnector(target);
|
|
2600
2628
|
const siteUrl = typeof s.site.hosting?.settings.siteUrl === "string" ? s.site.hosting.settings.siteUrl.replace(/\/+$/, "") : "";
|
|
2601
2629
|
return forms.publishForm(s.ctx, id, { put: (input) => connector.put(input), publicUrl: async (path) => siteUrl ? `${siteUrl}/${path}` : connector.publicUrl(path) });
|
|
@@ -2604,7 +2632,7 @@ const formsCommand = {
|
|
|
2604
2632
|
case "ingest": {
|
|
2605
2633
|
const apply = options.yes === true;
|
|
2606
2634
|
return withSession(io, options, { lock: apply }, async ({ ctx }) => {
|
|
2607
|
-
const { ingestInbox } = await import("./chunks/forms-
|
|
2635
|
+
const { ingestInbox } = await import("./chunks/forms-DJDop3XY.mjs");
|
|
2608
2636
|
const report = await ingestInbox(ctx, strOpt(options, "form"), { dryRun: !apply, limit: numOpt(options, "limit") });
|
|
2609
2637
|
return apply ? report : { needsConfirmation: true, ...report };
|
|
2610
2638
|
}, (r) => `${"needsConfirmation" in r ? "DRY RUN — " : ""}processed ${r.processed}: ${r.created} created, ${r.updated} updated, ${r.failed} failed`);
|
|
@@ -2740,7 +2768,7 @@ const deployAdminCommand = {
|
|
|
2740
2768
|
const sites = options.all === true ? listSites().sites.filter((s) => s.hosting) : [resolveSite(strOpt(options, "site"))];
|
|
2741
2769
|
if (!sites.length) throw new CliError("no-sites", "No registered CRM has a hosting.");
|
|
2742
2770
|
installBrowserEnv();
|
|
2743
|
-
const { adminOps, applyOps, buildConnector } = await import("./chunks/hosting-
|
|
2771
|
+
const { adminOps, applyOps, buildConnector } = await import("./chunks/hosting-C_UDyMkm.mjs");
|
|
2744
2772
|
const { hostingTargetOf: hostingTargetOf2 } = await Promise.resolve().then(() => session);
|
|
2745
2773
|
const plans = [];
|
|
2746
2774
|
for (const site of sites) {
|
|
@@ -2844,7 +2872,7 @@ async function runDoctor(site, opts = {}) {
|
|
|
2844
2872
|
installBrowserEnv();
|
|
2845
2873
|
try {
|
|
2846
2874
|
if (site.runtime.backend === "journal" && site.runtime.journal.connectorId === "git-pages") {
|
|
2847
|
-
const { probeTarget } = await import("./chunks/install-
|
|
2875
|
+
const { probeTarget } = await import("./chunks/install-D1lgtRIH.mjs");
|
|
2848
2876
|
const { dataTargetOf: dataTargetOf2 } = await Promise.resolve().then(() => session);
|
|
2849
2877
|
const probe = await probeTarget(dataTargetOf2(site), { requireSiteUrl: false, requirePrivate: true });
|
|
2850
2878
|
add(probe.ok ? { id: "data-repo", status: "ok", message: probe.detail } : { id: "data-repo", status: "fail", message: probe.detail, fix: "Make the data repository private and check the token's Contents permission." });
|
|
@@ -2854,6 +2882,15 @@ async function runDoctor(site, opts = {}) {
|
|
|
2854
2882
|
try {
|
|
2855
2883
|
const store = session$1.store;
|
|
2856
2884
|
add({ id: "data-access", status: "ok", message: `Dataset opened (${store.kind}${session$1.user ? `, acting as ${session$1.user.email} (${session$1.user.role})` : ""}).` });
|
|
2885
|
+
const { isFirebaseStore } = await import("./chunks/firebase-Bknru2pE.mjs");
|
|
2886
|
+
const load2 = isFirebaseStore(store) ? store.lastLoad() : null;
|
|
2887
|
+
if (load2) {
|
|
2888
|
+
add({
|
|
2889
|
+
id: "firestore-reads",
|
|
2890
|
+
status: "ok",
|
|
2891
|
+
message: load2.mode === "incremental" ? `Loaded from the local cache + changes: ${load2.reads} Firestore reads.` : `Full read: ${load2.reads} Firestore reads (the next commands read only what changed).`
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2857
2894
|
const { usersOf, objectsOf, pipelinesOf, settingsDoc, recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
|
|
2858
2895
|
const missing = [];
|
|
2859
2896
|
for (const id of ["companies", "people", "deals"]) if (!objectsOf(store).some((o) => o.id === id)) missing.push(`object ${id}`);
|
|
@@ -2861,7 +2898,7 @@ async function runDoctor(site, opts = {}) {
|
|
|
2861
2898
|
if (!settingsDoc(store)) missing.push("settings");
|
|
2862
2899
|
if (!usersOf(store).some((u) => u.role === "admin" && !u.disabled)) missing.push("an active admin user");
|
|
2863
2900
|
if (missing.length && opts.repair) {
|
|
2864
|
-
const { seedCrm } = await import("./chunks/seed-
|
|
2901
|
+
const { seedCrm } = await import("./chunks/seed-Bb26Zsni.mjs");
|
|
2865
2902
|
repaired = await seedCrm(session$1.system, { admin: site.user ? { name: site.user.split("@")[0], email: site.user } : void 0 });
|
|
2866
2903
|
add({ id: "dataset", status: "ok", message: `Repaired: seeded ${missing.join(", ")}.` });
|
|
2867
2904
|
} else {
|
|
@@ -3004,7 +3041,7 @@ const installCommand = {
|
|
|
3004
3041
|
const { resolvePlan } = await import("./chunks/plan-BmTat6-T.mjs");
|
|
3005
3042
|
const plan = resolvePlan(readPlan(planPath));
|
|
3006
3043
|
if (getSite(plan.alias)) throw new CliError("site-exists", `A site named "${plan.alias}" is already registered.`, "Use another alias, or `agentcrm site forget` it first.");
|
|
3007
|
-
const { checkPlan, runInstall } = await import("./chunks/install-
|
|
3044
|
+
const { checkPlan, runInstall } = await import("./chunks/install-D1lgtRIH.mjs");
|
|
3008
3045
|
io.err("Checking access…");
|
|
3009
3046
|
const checks = await checkPlan(plan);
|
|
3010
3047
|
const summary = {
|
|
@@ -3360,7 +3397,7 @@ const optionsCommand = {
|
|
|
3360
3397
|
async run({ io, options }) {
|
|
3361
3398
|
const rulesEmail = strOpt(options, "firebase-rules");
|
|
3362
3399
|
if (rulesEmail) {
|
|
3363
|
-
const { buildFirestoreRules } = await import("./chunks/firebaseRules-
|
|
3400
|
+
const { buildFirestoreRules } = await import("./chunks/firebaseRules-Jq85MBBN.mjs");
|
|
3364
3401
|
const rules = buildFirestoreRules({ adminEmail: rulesEmail });
|
|
3365
3402
|
printResult(io, { email: rulesEmail, rules, where: "Firebase console → Firestore Database → Rules → paste → Publish (or `firebase deploy --only firestore:rules`)." }, () => rules);
|
|
3366
3403
|
return;
|
|
@@ -3438,13 +3475,13 @@ const objectsCommand = {
|
|
|
3438
3475
|
switch (action) {
|
|
3439
3476
|
case "list":
|
|
3440
3477
|
return withSession(io, options, {}, async ({ ctx, store }) => {
|
|
3441
|
-
const { listObjects } = await import("./chunks/schema-
|
|
3478
|
+
const { listObjects } = await import("./chunks/schema-DOnnH2zL.mjs");
|
|
3442
3479
|
const { recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
|
|
3443
3480
|
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 }));
|
|
3444
3481
|
}, (rows) => table(rows, ["id", "labelPlural", "fields", "records", "standard"]));
|
|
3445
3482
|
case "get": {
|
|
3446
3483
|
const objectId = positional(positionals, 1, "object id", "objects get <id>");
|
|
3447
|
-
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/schema-
|
|
3484
|
+
return withSession(io, options, {}, async ({ ctx }) => (await import("./chunks/schema-DOnnH2zL.mjs")).describeSchema(ctx, objectId)[0]);
|
|
3448
3485
|
}
|
|
3449
3486
|
case "create": {
|
|
3450
3487
|
const data = jsonObjectOpt(options, "data") ?? {};
|
|
@@ -3457,7 +3494,7 @@ const objectsCommand = {
|
|
|
3457
3494
|
...strOpt(options, "color") ? { color: strOpt(options, "color") } : {}
|
|
3458
3495
|
};
|
|
3459
3496
|
if (!input.labelSingular || !input.labelPlural) usage("objects create needs --singular and --plural (or --data).");
|
|
3460
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-
|
|
3497
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-DOnnH2zL.mjs")).createObject(ctx, input));
|
|
3461
3498
|
}
|
|
3462
3499
|
case "update": {
|
|
3463
3500
|
const objectId = positional(positionals, 1, "object id", "objects update <id> …");
|
|
@@ -3469,12 +3506,12 @@ const objectsCommand = {
|
|
|
3469
3506
|
...strOpt(options, "label-field") ? { labelField: strOpt(options, "label-field") } : {}
|
|
3470
3507
|
};
|
|
3471
3508
|
if (!Object.keys(patch).length) usage("objects update needs --singular, --plural, --icon, --color or --label-field.");
|
|
3472
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-
|
|
3509
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-DOnnH2zL.mjs")).updateObject(ctx, objectId, patch));
|
|
3473
3510
|
}
|
|
3474
3511
|
case "delete": {
|
|
3475
3512
|
if (!id) usage("objects delete needs an object id.");
|
|
3476
3513
|
return withSession(io, options, { lock: options.yes === true }, async ({ ctx, store }) => {
|
|
3477
|
-
const { getObject, deleteObject } = await import("./chunks/schema-
|
|
3514
|
+
const { getObject, deleteObject } = await import("./chunks/schema-DOnnH2zL.mjs");
|
|
3478
3515
|
const { recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
|
|
3479
3516
|
const o = getObject(ctx, id);
|
|
3480
3517
|
const plan = { object: o.id, label: o.labelPlural, standard: o.standard, recordsDeleted: recordsOf(store, o.id, { includeDeleted: true }).length };
|
|
@@ -3532,7 +3569,7 @@ const fieldsCommand = {
|
|
|
3532
3569
|
...boolOpt(options, "unique") ? { unique: true } : {},
|
|
3533
3570
|
...strOpt(options, "description") ? { description: strOpt(options, "description") } : {}
|
|
3534
3571
|
};
|
|
3535
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-
|
|
3572
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-DOnnH2zL.mjs")).createField(ctx, objectId, input));
|
|
3536
3573
|
}
|
|
3537
3574
|
case "update": {
|
|
3538
3575
|
if (!fieldId) usage("fields update needs a field id.");
|
|
@@ -3549,12 +3586,12 @@ const fieldsCommand = {
|
|
|
3549
3586
|
...strOpt(options, "description") !== void 0 ? { description: strOpt(options, "description") } : {}
|
|
3550
3587
|
};
|
|
3551
3588
|
if (!Object.keys(patch).length) usage("fields update needs at least one change.");
|
|
3552
|
-
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-
|
|
3589
|
+
return withSession(io, options, { lock: true }, async ({ ctx }) => (await import("./chunks/schema-DOnnH2zL.mjs")).updateField(ctx, objectId, fieldId, patch));
|
|
3553
3590
|
}
|
|
3554
3591
|
case "delete": {
|
|
3555
3592
|
if (!fieldId) usage("fields delete needs a field id.");
|
|
3556
3593
|
return withSession(io, options, { lock: options.yes === true }, async ({ ctx, store }) => {
|
|
3557
|
-
const { getObject, deleteField } = await import("./chunks/schema-
|
|
3594
|
+
const { getObject, deleteField } = await import("./chunks/schema-DOnnH2zL.mjs");
|
|
3558
3595
|
const { recordsOf } = await import("./chunks/store-5gqRSKXg.mjs");
|
|
3559
3596
|
const field = getObject(ctx, objectId).fields.find((f) => f.id === fieldId);
|
|
3560
3597
|
if (!field) usage(`No field "${fieldId}" on ${objectId}.`, `\`agentcrm objects get ${objectId}\` lists them.`);
|
|
@@ -3568,6 +3605,50 @@ const fieldsCommand = {
|
|
|
3568
3605
|
}
|
|
3569
3606
|
}
|
|
3570
3607
|
};
|
|
3608
|
+
const schemaCommand = {
|
|
3609
|
+
name: "schema",
|
|
3610
|
+
usage: "schema apply <file|-> [--yes]",
|
|
3611
|
+
summary: "Bring the data model in line with a JSON description ({ objects: [{ id, labelSingular, labelPlural, icon, color, labelField, fields: [{ id, label, type, options, relation… }] }], pipelines: [{ id, name, object, stages }], views: [{ object, name, columns, filters, sorts, groupBy, shared }] }). Creates what is missing and updates what differs; never deletes, never changes a field type (reported as a conflict), never removes a select option or a stage; reports custom fields the description doesn't list. Prints the plan unless --yes.",
|
|
3612
|
+
subcommands: [{ name: "apply", usage: "schema apply <file|-> [--yes]", summary: "Apply a schema description (plan unless --yes).", writes: true }],
|
|
3613
|
+
options: [SITE_OPTION, AS_OPTION, YES_OPTION],
|
|
3614
|
+
async run({ io, options, positionals }) {
|
|
3615
|
+
const [action, source] = positionals;
|
|
3616
|
+
if (action !== "apply") usage(`Unknown schema action "${action ?? ""}".`, "Use schema apply <file|-> [--yes].");
|
|
3617
|
+
if (!source) usage("schema apply needs a file (or - for stdin).", "Example: agentcrm schema apply crm-schema.json");
|
|
3618
|
+
const { readTextValue: readTextValue2 } = await Promise.resolve().then(() => util);
|
|
3619
|
+
const text = readTextValue2(source === "-" ? "-" : `@${source}`, "schema");
|
|
3620
|
+
let raw;
|
|
3621
|
+
try {
|
|
3622
|
+
raw = JSON.parse(text);
|
|
3623
|
+
} catch (err) {
|
|
3624
|
+
usage(`The schema is not valid JSON: ${err.message}`);
|
|
3625
|
+
}
|
|
3626
|
+
const apply = options.yes === true;
|
|
3627
|
+
const { applySchema, parseSchemaSpec } = await import("./chunks/schemaApply-DKHipylx.mjs");
|
|
3628
|
+
const spec = parseSchemaSpec(raw);
|
|
3629
|
+
return withSession(
|
|
3630
|
+
io,
|
|
3631
|
+
options,
|
|
3632
|
+
{ lock: apply },
|
|
3633
|
+
async ({ ctx }) => {
|
|
3634
|
+
if (apply) return applySchema(ctx, spec);
|
|
3635
|
+
const { dryRun: dryRun2 } = await Promise.resolve().then(() => dryRun$1);
|
|
3636
|
+
const { result } = await dryRun2(ctx, (copy) => applySchema(copy, spec));
|
|
3637
|
+
return result.changes.length ? { needsConfirmation: true, plan: result } : { ...result, upToDate: true };
|
|
3638
|
+
},
|
|
3639
|
+
(r) => {
|
|
3640
|
+
const report = "needsConfirmation" in r ? r.plan : r;
|
|
3641
|
+
const lines = report.changes.map((c) => ` ${c.action} ${c.kind} ${c.target}${c.changes?.length ? ` (${c.changes.join(", ")})` : ""}`);
|
|
3642
|
+
const extra = [
|
|
3643
|
+
...report.conflicts.map((c) => ` conflict: ${c}`),
|
|
3644
|
+
...report.extraFields.length ? [` not in the schema (kept): ${report.extraFields.join(", ")}`] : []
|
|
3645
|
+
];
|
|
3646
|
+
if ("needsConfirmation" in r) return [`Would change ${report.changes.length} thing(s):`, ...lines, ...extra, "Nothing changed — re-run with --yes once the user agrees."].join("\n");
|
|
3647
|
+
return [report.changes.length ? `Applied ${report.changes.length} change(s):` : "The data model already matches the schema.", ...lines, ...extra].join("\n");
|
|
3648
|
+
}
|
|
3649
|
+
);
|
|
3650
|
+
}
|
|
3651
|
+
};
|
|
3571
3652
|
const MIME = {
|
|
3572
3653
|
".html": "text/html; charset=utf-8",
|
|
3573
3654
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -3861,7 +3942,7 @@ const toolsCommand = {
|
|
|
3861
3942
|
async run({ io, options, positionals }) {
|
|
3862
3943
|
const [action = "list"] = positionals;
|
|
3863
3944
|
if (action === "list") {
|
|
3864
|
-
const { listAiTools, AI_TOOLS } = await import("./chunks/tools-
|
|
3945
|
+
const { listAiTools, AI_TOOLS } = await import("./chunks/tools-CCk24tdh.mjs");
|
|
3865
3946
|
const builtin = new Set(AI_TOOLS.map((t) => t.name));
|
|
3866
3947
|
const shape = () => listAiTools().map((t) => ({ name: t.name, description: t.description, mutating: t.mutating, source: builtin.has(t.name) ? "builtin" : "extension", inputSchema: t.inputSchema }));
|
|
3867
3948
|
const human = (r) => table(r.tools, ["name", "mutating", "source", "description"]);
|
|
@@ -3881,7 +3962,7 @@ const toolsCommand = {
|
|
|
3881
3962
|
}
|
|
3882
3963
|
if (action === "call") {
|
|
3883
3964
|
const name2 = positional(positionals, 1, "tool name", "tools call <name> --input <json>");
|
|
3884
|
-
const { findTool, callTool, listAiTools } = await import("./chunks/tools-
|
|
3965
|
+
const { findTool, callTool, listAiTools } = await import("./chunks/tools-CCk24tdh.mjs");
|
|
3885
3966
|
const input = jsonObjectOpt(options, "input") ?? {};
|
|
3886
3967
|
const builtin = findTool(name2);
|
|
3887
3968
|
return withSession(io, options, { lock: builtin ? builtin.mutating : true }, async ({ ctx }) => {
|
|
@@ -3903,8 +3984,8 @@ const mcpCommand = {
|
|
|
3903
3984
|
const log = (msg) => process.stderr.write(`${msg}
|
|
3904
3985
|
`);
|
|
3905
3986
|
for (const w of session2.warnings) log(`[agentcrm mcp] note: ${w}`);
|
|
3906
|
-
const { listAiTools } = await import("./chunks/tools-
|
|
3907
|
-
const { createMcpServer, serveStdio } = await import("./chunks/server-
|
|
3987
|
+
const { listAiTools } = await import("./chunks/tools-CCk24tdh.mjs");
|
|
3988
|
+
const { createMcpServer, serveStdio } = await import("./chunks/server-Bch4TQon.mjs");
|
|
3908
3989
|
let lastRefresh = Date.now();
|
|
3909
3990
|
const server = createMcpServer({
|
|
3910
3991
|
readOnly,
|
|
@@ -4006,6 +4087,7 @@ const COMMANDS = [
|
|
|
4006
4087
|
deployAdminCommand,
|
|
4007
4088
|
recordsCommand,
|
|
4008
4089
|
objectsCommand,
|
|
4090
|
+
schemaCommand,
|
|
4009
4091
|
fieldsCommand,
|
|
4010
4092
|
activitiesCommand,
|
|
4011
4093
|
notesCommand,
|
|
@@ -4102,14 +4184,17 @@ export {
|
|
|
4102
4184
|
findHosting as e,
|
|
4103
4185
|
findBackend as f,
|
|
4104
4186
|
getCredential as g,
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4187
|
+
readJsonFile as h,
|
|
4188
|
+
homePath as i,
|
|
4189
|
+
openStore as j,
|
|
4190
|
+
installBrowserEnv as k,
|
|
4191
|
+
distRoot as l,
|
|
4108
4192
|
nodeImportBundle as n,
|
|
4109
4193
|
ownPackageRoot as o,
|
|
4110
4194
|
packageRoot as p,
|
|
4111
4195
|
readVersionInfo as r,
|
|
4112
4196
|
setCredential as s,
|
|
4113
4197
|
toCliError as t,
|
|
4114
|
-
validateAlias as v
|
|
4198
|
+
validateAlias as v,
|
|
4199
|
+
writeJsonFile as w
|
|
4115
4200
|
};
|