@datasynx/agentic-crm 0.1.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/LICENSE +21 -0
- package/README.md +767 -0
- package/dist/agent-config-zPvcqu07.js +14 -0
- package/dist/agent-config-zPvcqu07.js.map +1 -0
- package/dist/approvals-DpjxGHFp.js +67 -0
- package/dist/approvals-DpjxGHFp.js.map +1 -0
- package/dist/ask-CID3jnuL.js +52 -0
- package/dist/ask-CID3jnuL.js.map +1 -0
- package/dist/audit-log-DNMY9mUZ.js +49 -0
- package/dist/audit-log-DNMY9mUZ.js.map +1 -0
- package/dist/auth-CyFuu9X_.js +2 -0
- package/dist/auth-DFWwWcYD.js +93 -0
- package/dist/auth-DFWwWcYD.js.map +1 -0
- package/dist/autofill-Di_-SP7t.js +51 -0
- package/dist/autofill-Di_-SP7t.js.map +1 -0
- package/dist/backup-CeMk9z86.js +417 -0
- package/dist/backup-CeMk9z86.js.map +1 -0
- package/dist/backup-f_hC7rBV.js +2 -0
- package/dist/calendly-Bft_wwji.js +52 -0
- package/dist/calendly-Bft_wwji.js.map +1 -0
- package/dist/calendly-D3coO92o.cjs +53 -0
- package/dist/calendly-D3coO92o.cjs.map +1 -0
- package/dist/chunk-DakpK96I.cjs +43 -0
- package/dist/churn-C28IgnAj.js +54 -0
- package/dist/churn-C28IgnAj.js.map +1 -0
- package/dist/cli.js +4396 -0
- package/dist/cli.js.map +1 -0
- package/dist/colors-BG07TZQz.js +11 -0
- package/dist/colors-BG07TZQz.js.map +1 -0
- package/dist/compliance-B1kk5-YS.js +115 -0
- package/dist/compliance-B1kk5-YS.js.map +1 -0
- package/dist/compliance-B91zNvCR.cjs +156 -0
- package/dist/compliance-B91zNvCR.cjs.map +1 -0
- package/dist/compliance-CKSBoQUe.js +118 -0
- package/dist/compliance-CKSBoQUe.js.map +1 -0
- package/dist/compliance-CujOqAKk.js +2 -0
- package/dist/context-builder-BzWAp3Zs.js +96 -0
- package/dist/context-builder-BzWAp3Zs.js.map +1 -0
- package/dist/context-builder-DlrRcqmJ.js +2 -0
- package/dist/conversation-intel-mm7Lhemh.js +72 -0
- package/dist/conversation-intel-mm7Lhemh.js.map +1 -0
- package/dist/custom-fields-CzNeD3_v.js +2 -0
- package/dist/custom-fields-Pl2t9xzp.js +73 -0
- package/dist/custom-fields-Pl2t9xzp.js.map +1 -0
- package/dist/custom-objects-BHgn1GEX.js +78 -0
- package/dist/custom-objects-BHgn1GEX.js.map +1 -0
- package/dist/custom-objects-CIFrmQ2V.js +2 -0
- package/dist/customer-dir-DIylZ8Q6.js +75 -0
- package/dist/customer-dir-DIylZ8Q6.js.map +1 -0
- package/dist/daemon/worker.js +207 -0
- package/dist/daemon/worker.js.map +1 -0
- package/dist/enrichment-3XvgGDfB.js +103 -0
- package/dist/enrichment-3XvgGDfB.js.map +1 -0
- package/dist/file-lock-B_zi7NQl.js +22 -0
- package/dist/file-lock-B_zi7NQl.js.map +1 -0
- package/dist/gmail-auth-BP6cJwfw.js +40 -0
- package/dist/gmail-auth-BP6cJwfw.js.map +1 -0
- package/dist/gmail-auth-DxakCtGm.cjs +44 -0
- package/dist/gmail-auth-DxakCtGm.cjs.map +1 -0
- package/dist/gmail-auth-OComS92L.js +40 -0
- package/dist/gmail-auth-OComS92L.js.map +1 -0
- package/dist/gmail-push-watch-DELQFMPk.js +20 -0
- package/dist/gmail-push-watch-DELQFMPk.js.map +1 -0
- package/dist/gmail-sender-StTpJ9Ub.js +32 -0
- package/dist/gmail-sender-StTpJ9Ub.js.map +1 -0
- package/dist/gmail-sync-DIaxInDT.js +204 -0
- package/dist/gmail-sync-DIaxInDT.js.map +1 -0
- package/dist/gmail-sync-hHm9gaWd.cjs +218 -0
- package/dist/gmail-sync-hHm9gaWd.cjs.map +1 -0
- package/dist/gmail-sync-rQaVqKWd.js +214 -0
- package/dist/gmail-sync-rQaVqKWd.js.map +1 -0
- package/dist/gmail-webhook-handler-DS7OlRPX.js +3 -0
- package/dist/gmail-webhook-handler-e5Od25FX.js +97 -0
- package/dist/gmail-webhook-handler-e5Od25FX.js.map +1 -0
- package/dist/goal-engine-CUZSpERI.js +2 -0
- package/dist/goal-engine-KpBftn4V.js +295 -0
- package/dist/goal-engine-KpBftn4V.js.map +1 -0
- package/dist/google-drive-sync-DEPcqFca.js +105 -0
- package/dist/google-drive-sync-DEPcqFca.js.map +1 -0
- package/dist/hybrid-search-BmHttLrR.js +40 -0
- package/dist/hybrid-search-BmHttLrR.js.map +1 -0
- package/dist/hygiene-DZqfYpFf.js +38 -0
- package/dist/hygiene-DZqfYpFf.js.map +1 -0
- package/dist/identity-CI6olMNm.js +41 -0
- package/dist/identity-CI6olMNm.js.map +1 -0
- package/dist/identity-gyfWdrcX.js +2 -0
- package/dist/import-hubspot-BaK71U_K.js +588 -0
- package/dist/import-hubspot-BaK71U_K.js.map +1 -0
- package/dist/index-V8BFaH-b.d.ts +539 -0
- package/dist/index-V8BFaH-b.d.ts.map +1 -0
- package/dist/index-YqwMd6aQ.d.cts +538 -0
- package/dist/index-YqwMd6aQ.d.cts.map +1 -0
- package/dist/index.cjs +185 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +538 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +539 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +165 -0
- package/dist/index.js.map +1 -0
- package/dist/interactions-writer-CrPStUll.cjs +77 -0
- package/dist/interactions-writer-CrPStUll.cjs.map +1 -0
- package/dist/interactions-writer-DO3KcSR3.js +52 -0
- package/dist/interactions-writer-DO3KcSR3.js.map +1 -0
- package/dist/interactions-writer-SLHnoEeE.js +46 -0
- package/dist/interactions-writer-SLHnoEeE.js.map +1 -0
- package/dist/interactions-writer-dSPy1XfO.js +2 -0
- package/dist/knowledge-base-D0Fh40kc.js +1013 -0
- package/dist/knowledge-base-D0Fh40kc.js.map +1 -0
- package/dist/lancedb-CCBbpulq.js +2 -0
- package/dist/lancedb-rlvWoPwl.js +98 -0
- package/dist/lancedb-rlvWoPwl.js.map +1 -0
- package/dist/lead-model-BCFzyktm.js +109 -0
- package/dist/lead-model-BCFzyktm.js.map +1 -0
- package/dist/llm-DEjWcqmW.js +2 -0
- package/dist/llm-DvzZqva0.js +372 -0
- package/dist/llm-DvzZqva0.js.map +1 -0
- package/dist/llm-Z8RIYkpF.js +174 -0
- package/dist/llm-Z8RIYkpF.js.map +1 -0
- package/dist/llm-iijeXmgq.cjs +198 -0
- package/dist/llm-iijeXmgq.cjs.map +1 -0
- package/dist/mcp-CdTJWTJf.d.cts +12 -0
- package/dist/mcp-CdTJWTJf.d.cts.map +1 -0
- package/dist/mcp-CdTJWTJf.d.ts +12 -0
- package/dist/mcp-CdTJWTJf.d.ts.map +1 -0
- package/dist/mcp.cjs +7464 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +12 -0
- package/dist/mcp.d.cts.map +1 -0
- package/dist/mcp.d.ts +12 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +7448 -0
- package/dist/mcp.js.map +1 -0
- package/dist/memory-Bb6ky3kb.js +58 -0
- package/dist/memory-Bb6ky3kb.js.map +1 -0
- package/dist/memory-Cy6-Tbyl.js +2 -0
- package/dist/metrics-DH8wHvya.js +26 -0
- package/dist/metrics-DH8wHvya.js.map +1 -0
- package/dist/microsoft-auth-B8_S45gh.js +17 -0
- package/dist/microsoft-auth-B8_S45gh.js.map +1 -0
- package/dist/microsoft-calendar-B6MMtUQK.js +67 -0
- package/dist/microsoft-calendar-B6MMtUQK.js.map +1 -0
- package/dist/microsoft-sync-CpZVoSuq.js +68 -0
- package/dist/microsoft-sync-CpZVoSuq.js.map +1 -0
- package/dist/nba-3wanmJ0U.js +48 -0
- package/dist/nba-3wanmJ0U.js.map +1 -0
- package/dist/notification-dispatcher-0vYNngWe.js +97 -0
- package/dist/notification-dispatcher-0vYNngWe.js.map +1 -0
- package/dist/opportunity-score-BTMOQSTV.js +47 -0
- package/dist/opportunity-score-BTMOQSTV.js.map +1 -0
- package/dist/pipedrive-client-CdGKpH9b.js +17 -0
- package/dist/pipedrive-client-CdGKpH9b.js.map +1 -0
- package/dist/pipeline-writer-BqBrYrQc.js +2 -0
- package/dist/pipeline-writer-BvVquKIe.js +96 -0
- package/dist/pipeline-writer-BvVquKIe.js.map +1 -0
- package/dist/pipeline-writer-N2omexxp.cjs +121 -0
- package/dist/pipeline-writer-N2omexxp.cjs.map +1 -0
- package/dist/pipeline-writer-eufx_0o1.js +102 -0
- package/dist/pipeline-writer-eufx_0o1.js.map +1 -0
- package/dist/proactive-agent-BgQXw3ac.js +96 -0
- package/dist/proactive-agent-BgQXw3ac.js.map +1 -0
- package/dist/proactive-worker-BrLHNhjH.js +229 -0
- package/dist/proactive-worker-BrLHNhjH.js.map +1 -0
- package/dist/push-manager-CdqIIkuh.js +108 -0
- package/dist/push-manager-CdqIIkuh.js.map +1 -0
- package/dist/push-manager-CowY-0IK.js +2 -0
- package/dist/quote-generator-BfwENXzg.js +133 -0
- package/dist/quote-generator-BfwENXzg.js.map +1 -0
- package/dist/quote-generator-OhSFsi3x.js +2 -0
- package/dist/rbac-C7c8tcES.js +2 -0
- package/dist/rbac-CTIktZaC.js +91 -0
- package/dist/rbac-CTIktZaC.js.map +1 -0
- package/dist/relationship-health-odxEoQdJ.js +454 -0
- package/dist/relationship-health-odxEoQdJ.js.map +1 -0
- package/dist/revenue-simulation-BJdRTEHc.js +2 -0
- package/dist/revenue-simulation-Bqf2DLVB.js +251 -0
- package/dist/revenue-simulation-Bqf2DLVB.js.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/salesforce-client-rhZFa_p5.js +51 -0
- package/dist/salesforce-client-rhZFa_p5.js.map +1 -0
- package/dist/segments-BqcD5HIl.js +61 -0
- package/dist/segments-BqcD5HIl.js.map +1 -0
- package/dist/sequence-engine-CCTHEBgi.js +2 -0
- package/dist/sequence-engine-J1lTW_in.js +91 -0
- package/dist/sequence-engine-J1lTW_in.js.map +1 -0
- package/dist/sequence-store-DaaWr0Os.js +221 -0
- package/dist/sequence-store-DaaWr0Os.js.map +1 -0
- package/dist/server-Dyva03K8.js +4287 -0
- package/dist/server-Dyva03K8.js.map +1 -0
- package/dist/session-B9AilxOE.js +81 -0
- package/dist/session-B9AilxOE.js.map +1 -0
- package/dist/session-D0qFkBla.cjs +82 -0
- package/dist/session-D0qFkBla.cjs.map +1 -0
- package/dist/session-D9ub6Wl1.js +79 -0
- package/dist/session-D9ub6Wl1.js.map +1 -0
- package/dist/session-mWHA71Lw.js +2 -0
- package/dist/session-store-B0QZE8Bx.cjs +697 -0
- package/dist/session-store-B0QZE8Bx.cjs.map +1 -0
- package/dist/session-store-C8tEvMPw.js +543 -0
- package/dist/session-store-C8tEvMPw.js.map +1 -0
- package/dist/session-store-CEa39Dxs.js +15 -0
- package/dist/session-store-CEa39Dxs.js.map +1 -0
- package/dist/sla-engine-5IhTsBUR.js +2 -0
- package/dist/sla-engine-BqX-7u-7.js +53 -0
- package/dist/sla-engine-BqX-7u-7.js.map +1 -0
- package/dist/sop-DkhVChGy.js +2 -0
- package/dist/sop-Vp0UPWFW.js +70 -0
- package/dist/sop-Vp0UPWFW.js.map +1 -0
- package/dist/survey-engine-C06hcQt3.js +2 -0
- package/dist/survey-engine-DBjCYqCv.js +147 -0
- package/dist/survey-engine-DBjCYqCv.js.map +1 -0
- package/dist/sync-state-ChaLbamC.js +33 -0
- package/dist/sync-state-ChaLbamC.js.map +1 -0
- package/dist/sync-state-CwLSt_1m.js +2 -0
- package/dist/ticket-writer-CjqKeIRD.js +2 -0
- package/dist/ticket-writer-j2oX_Wal.js +134 -0
- package/dist/ticket-writer-j2oX_Wal.js.map +1 -0
- package/dist/tone-Bdm5uaht.js +48 -0
- package/dist/tone-Bdm5uaht.js.map +1 -0
- package/dist/tone-DRKlZgPr.cjs +43 -0
- package/dist/tone-DRKlZgPr.cjs.map +1 -0
- package/dist/tone-vNb2DAAD.js +39 -0
- package/dist/tone-vNb2DAAD.js.map +1 -0
- package/dist/transcript-watcher-CL2QUygI.js +132 -0
- package/dist/transcript-watcher-CL2QUygI.js.map +1 -0
- package/dist/unmatched-transcripts-BsH5bhkU.js +26 -0
- package/dist/unmatched-transcripts-BsH5bhkU.js.map +1 -0
- package/dist/unmatched-transcripts-D0PrJ9iz.js +2 -0
- package/dist/update-deal-BNwPGaTV.js +2 -0
- package/dist/update-deal-DKC79skb.js +91 -0
- package/dist/update-deal-DKC79skb.js.map +1 -0
- package/dist/usage-CClTf5e6.cjs +57 -0
- package/dist/usage-CClTf5e6.cjs.map +1 -0
- package/dist/usage-D0-TYJkw.js +93 -0
- package/dist/usage-D0-TYJkw.js.map +1 -0
- package/dist/usage-D0u9a-lV.js +54 -0
- package/dist/usage-D0u9a-lV.js.map +1 -0
- package/dist/vault-C1D3zScD.js +2 -0
- package/dist/vault-DXCg29W-.js +86 -0
- package/dist/vault-DXCg29W-.js.map +1 -0
- package/dist/webhooks-7EpA05Qr.js +138 -0
- package/dist/webhooks-7EpA05Qr.js.map +1 -0
- package/dist/webhooks-BO2UAnmn.js +94 -0
- package/dist/webhooks-BO2UAnmn.js.map +1 -0
- package/dist/webhooks-Xn6zO6kd.cjs +97 -0
- package/dist/webhooks-Xn6zO6kd.cjs.map +1 -0
- package/dist/write-queue-BDolUxfs.cjs +26 -0
- package/dist/write-queue-BDolUxfs.cjs.map +1 -0
- package/dist/write-queue-IbsAjUnh.js +21 -0
- package/dist/write-queue-IbsAjUnh.js.map +1 -0
- package/package.json +142 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { C as readMainFacts, S as listCustomerSlugs, T as MainFactsSchema, _ as info, b as customerExists, c as filterAuditLog, g as error, h as bold, i as canSeeCustomer, m as runBackup, n as getSession, o as getRbacConfig, r as setSession, s as getRole, t as clearSession, u as readAuditLog, v as success, w as writeMainFacts, x as ensureCustomerDir, y as warning } from "./session-store-C8tEvMPw.js";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import slugify from "slug";
|
|
6
|
+
import matter from "gray-matter";
|
|
7
|
+
//#region src/commands/create.ts
|
|
8
|
+
async function createCustomer(opts) {
|
|
9
|
+
const id = slugify(opts.name, { lower: true });
|
|
10
|
+
const dataDir = opts.dataDir ?? process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
11
|
+
await ensureCustomerDir(dataDir, id);
|
|
12
|
+
const dir = path.join(dataDir, "customers", id);
|
|
13
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
14
|
+
await writeMainFacts(dataDir, id, {
|
|
15
|
+
name: opts.name,
|
|
16
|
+
domain: opts.domain,
|
|
17
|
+
email: opts.email,
|
|
18
|
+
relationship_stage: "prospect",
|
|
19
|
+
tags: [],
|
|
20
|
+
currency: "EUR",
|
|
21
|
+
created: today,
|
|
22
|
+
updated: today
|
|
23
|
+
});
|
|
24
|
+
const interactionsPath = path.join(dir, "interactions.md");
|
|
25
|
+
if (!fs.existsSync(interactionsPath)) fs.writeFileSync(interactionsPath, `# Interactions — ${opts.name}\n\n`);
|
|
26
|
+
const pipelinePath = path.join(dir, "pipeline.md");
|
|
27
|
+
if (!fs.existsSync(pipelinePath)) fs.writeFileSync(pipelinePath, `# Pipeline — ${opts.name}\n\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\n|---|---|---|---|---|---|---|---|\n`);
|
|
28
|
+
const sourcesPath = path.join(dir, "sources.json");
|
|
29
|
+
if (!fs.existsSync(sourcesPath)) {
|
|
30
|
+
const sources = {
|
|
31
|
+
gmail: {
|
|
32
|
+
type: "gmail",
|
|
33
|
+
query: opts.domain ? `from:${opts.domain} OR to:${opts.domain}` : opts.email ? `from:${opts.email} OR to:${opts.email}` : "",
|
|
34
|
+
enabled: true
|
|
35
|
+
},
|
|
36
|
+
version: 1,
|
|
37
|
+
created: (/* @__PURE__ */ new Date()).toISOString()
|
|
38
|
+
};
|
|
39
|
+
fs.writeFileSync(sourcesPath, JSON.stringify(sources, null, 2));
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
id,
|
|
43
|
+
dir
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
new Command("create").argument("<name>", "Customer name").option("--domain <domain>", "Primary domain (for Gmail sync)").option("--email <email>", "Primary contact email").action(async (name, opts) => {
|
|
47
|
+
try {
|
|
48
|
+
const { id, dir } = await createCustomer({
|
|
49
|
+
name,
|
|
50
|
+
...opts
|
|
51
|
+
});
|
|
52
|
+
console.log(success(`✓ Created customer: ${bold(id)}`));
|
|
53
|
+
console.log(` Dir: ${dir}`);
|
|
54
|
+
console.log(` Files: main_facts.md, interactions.md, pipeline.md, sources.json`);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error(error(`✗ ${err.message}`));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/commands/audit.ts
|
|
62
|
+
const SEP = "─".repeat(70);
|
|
63
|
+
async function runAudit(opts, dataDir) {
|
|
64
|
+
const dir = dataDir ?? process.cwd();
|
|
65
|
+
const limit = opts.limit ?? 20;
|
|
66
|
+
const entries = filterAuditLog(readAuditLog(dir), {
|
|
67
|
+
...opts.slug !== void 0 ? { slug: opts.slug } : {},
|
|
68
|
+
...opts.actor !== void 0 ? { actor: opts.actor } : {},
|
|
69
|
+
limit
|
|
70
|
+
});
|
|
71
|
+
console.log(SEP);
|
|
72
|
+
console.log(" DatasynxOpenCRM — Audit Trail");
|
|
73
|
+
if (opts.slug) console.log(` Customer: ${opts.slug}`);
|
|
74
|
+
if (opts.actor) console.log(` Actor: ${opts.actor}`);
|
|
75
|
+
console.log(SEP);
|
|
76
|
+
if (entries.length === 0) {
|
|
77
|
+
console.log(" No audit entries found.");
|
|
78
|
+
console.log(SEP);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const entry of entries) console.log(` ${entry.timestamp} ${entry.actor.padEnd(12)} ${entry.tool.padEnd(20)} ${entry.slug.padEnd(20)} ${entry.summary}`);
|
|
82
|
+
console.log(SEP);
|
|
83
|
+
console.log(` ${entries.length} entr${entries.length === 1 ? "y" : "ies"} shown`);
|
|
84
|
+
console.log(SEP);
|
|
85
|
+
}
|
|
86
|
+
new Command("audit").description("Show CRM audit trail — who changed what and when").option("--slug <slug>", "Filter by customer slug").option("--actor <actor>", "Filter by actor").option("--limit <n>", "Number of entries to show (default: 20)", parseInt).option("--tail", "Show all new entries (simplified: shows current entries)").action((opts) => runAudit(opts, process.env["DXCRM_DATA_DIR"]));
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/commands/validate.ts
|
|
89
|
+
const RECOVERABLE_DEFAULTS = {
|
|
90
|
+
tags: [],
|
|
91
|
+
currency: "EUR"
|
|
92
|
+
};
|
|
93
|
+
function applyFix(factsPath, content, data) {
|
|
94
|
+
const fixed = [];
|
|
95
|
+
const patched = { ...data };
|
|
96
|
+
for (const [field, defaultValue] of Object.entries(RECOVERABLE_DEFAULTS)) if (patched[field] === void 0 || patched[field] === null) {
|
|
97
|
+
patched[field] = defaultValue;
|
|
98
|
+
fixed.push(`${field} → ${JSON.stringify(defaultValue)}`);
|
|
99
|
+
}
|
|
100
|
+
if (patched["updated"] === void 0 && patched["created"]) {
|
|
101
|
+
patched["updated"] = patched["created"];
|
|
102
|
+
fixed.push(`updated → ${String(patched["created"])}`);
|
|
103
|
+
}
|
|
104
|
+
if (fixed.length === 0) return null;
|
|
105
|
+
const parsed = matter(content);
|
|
106
|
+
const newContent = matter.stringify(parsed.content, patched);
|
|
107
|
+
fs.writeFileSync(factsPath, newContent);
|
|
108
|
+
return {
|
|
109
|
+
fixed,
|
|
110
|
+
content: newContent
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async function runValidate(opts, dataDir) {
|
|
114
|
+
const customersDir = path.join(dataDir, "customers");
|
|
115
|
+
if (!fs.existsSync(customersDir)) {
|
|
116
|
+
console.log(warning("⚠ No customers directory found."));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const slugs = listCustomerSlugs(dataDir);
|
|
120
|
+
let errorCount = 0;
|
|
121
|
+
let fixedCount = 0;
|
|
122
|
+
for (const slug of slugs) {
|
|
123
|
+
const factsPath = path.join(customersDir, slug, "main_facts.md");
|
|
124
|
+
const interactionsPath = path.join(customersDir, slug, "interactions.md");
|
|
125
|
+
if (!fs.existsSync(factsPath)) {
|
|
126
|
+
console.log(error(`✗ ${slug}: missing main_facts.md`));
|
|
127
|
+
errorCount++;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
let content = fs.readFileSync(factsPath, "utf-8");
|
|
132
|
+
const { data } = matter(content);
|
|
133
|
+
if (opts.fix) {
|
|
134
|
+
const result = applyFix(factsPath, content, data);
|
|
135
|
+
if (result) {
|
|
136
|
+
content = result.content;
|
|
137
|
+
fixedCount++;
|
|
138
|
+
console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(", ")}`));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const { data: refetchedData } = matter(content);
|
|
142
|
+
MainFactsSchema.parse(refetchedData);
|
|
143
|
+
if (!fs.existsSync(interactionsPath)) console.log(warning(`⚠ ${slug}: missing interactions.md`));
|
|
144
|
+
else console.log(success(`✓ ${slug}`));
|
|
145
|
+
} catch (err) {
|
|
146
|
+
console.log(error(`✗ ${slug}: ${err.message}`));
|
|
147
|
+
errorCount++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (opts.fix && fixedCount > 0) console.log(info(`\n⚙ Fixed ${fixedCount} customer(s).`));
|
|
151
|
+
if (errorCount > 0) {
|
|
152
|
+
console.error(error(`\n${errorCount} error(s) found.`));
|
|
153
|
+
process.exit(1);
|
|
154
|
+
} else console.log(success("\n✓ All customers valid."));
|
|
155
|
+
}
|
|
156
|
+
new Command("validate").option("--fix", "Auto-fix recoverable issues").action(async (opts) => {
|
|
157
|
+
await runValidate(opts, process.env["DXCRM_DATA_DIR"] ?? process.cwd());
|
|
158
|
+
});
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/version.ts
|
|
161
|
+
const VERSION = "0.1.0";
|
|
162
|
+
//#endregion
|
|
163
|
+
export { VERSION, canSeeCustomer, clearSession, createCustomer, customerExists, filterAuditLog, getRbacConfig, getRole, getSession, readAuditLog, readMainFacts, runAudit, runBackup, runValidate, setSession };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/commands/create.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/version.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport slugify from \"slug\";\nimport { ensureCustomerDir, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { success, error, bold } from \"../ui/colors.js\";\n\nexport async function createCustomer(opts: {\n name: string;\n domain?: string;\n email?: string;\n dataDir?: string;\n}): Promise<{ id: string; dir: string }> {\n const id = slugify(opts.name, { lower: true });\n const dataDir = opts.dataDir ?? process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n await ensureCustomerDir(dataDir, id);\n const dir = path.join(dataDir, \"customers\", id);\n\n // Write main_facts.md\n const today = new Date().toISOString().slice(0, 10);\n await writeMainFacts(dataDir, id, {\n name: opts.name,\n domain: opts.domain,\n email: opts.email,\n relationship_stage: \"prospect\",\n tags: [],\n currency: \"EUR\",\n created: today,\n updated: today,\n });\n\n // Create interactions.md\n const interactionsPath = path.join(dir, \"interactions.md\");\n if (!fs.existsSync(interactionsPath)) {\n fs.writeFileSync(interactionsPath, `# Interactions — ${opts.name}\\n\\n`);\n }\n\n // Create pipeline.md\n const pipelinePath = path.join(dir, \"pipeline.md\");\n if (!fs.existsSync(pipelinePath)) {\n fs.writeFileSync(\n pipelinePath,\n `# Pipeline — ${opts.name}\\n\\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\\n|---|---|---|---|---|---|---|---|\\n`\n );\n }\n\n // Create sources.json\n const sourcesPath = path.join(dir, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) {\n const gmailQuery = opts.domain\n ? `from:${opts.domain} OR to:${opts.domain}`\n : opts.email\n ? `from:${opts.email} OR to:${opts.email}`\n : \"\";\n const sources = {\n gmail: {\n type: \"gmail\",\n query: gmailQuery,\n enabled: true,\n },\n version: 1,\n created: new Date().toISOString(),\n };\n fs.writeFileSync(sourcesPath, JSON.stringify(sources, null, 2));\n }\n\n return { id, dir };\n}\n\nexport const createCommand = new Command(\"create\")\n .argument(\"<name>\", \"Customer name\")\n .option(\"--domain <domain>\", \"Primary domain (for Gmail sync)\")\n .option(\"--email <email>\", \"Primary contact email\")\n .action(async (name: string, opts: { domain?: string; email?: string }) => {\n try {\n const { id, dir } = await createCustomer({ name, ...opts });\n console.log(success(`✓ Created customer: ${bold(id)}`));\n console.log(` Dir: ${dir}`);\n console.log(` Files: main_facts.md, interactions.md, pipeline.md, sources.json`);\n } catch (err) {\n console.error(error(`✗ ${(err as Error).message}`));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { readAuditLog, filterAuditLog } from \"../fs/audit-log.js\";\n\nconst SEP = \"─\".repeat(70);\n\nexport async function runAudit(\n opts: {\n slug?: string;\n actor?: string;\n limit?: number;\n tail?: boolean;\n },\n dataDir?: string\n): Promise<void> {\n const dir = dataDir ?? process.cwd();\n const limit = opts.limit ?? 20;\n\n const allEntries = readAuditLog(dir);\n const entries = filterAuditLog(allEntries, {\n ...(opts.slug !== undefined ? { slug: opts.slug } : {}),\n ...(opts.actor !== undefined ? { actor: opts.actor } : {}),\n limit,\n });\n\n console.log(SEP);\n console.log(\" DatasynxOpenCRM — Audit Trail\");\n\n if (opts.slug) console.log(` Customer: ${opts.slug}`);\n if (opts.actor) console.log(` Actor: ${opts.actor}`);\n\n console.log(SEP);\n\n if (entries.length === 0) {\n console.log(\" No audit entries found.\");\n console.log(SEP);\n return;\n }\n\n for (const entry of entries) {\n console.log(\n ` ${entry.timestamp} ${entry.actor.padEnd(12)} ${entry.tool.padEnd(20)} ${entry.slug.padEnd(20)} ${entry.summary}`\n );\n }\n\n console.log(SEP);\n console.log(` ${entries.length} entr${entries.length === 1 ? \"y\" : \"ies\"} shown`);\n console.log(SEP);\n}\n\nexport const auditCommand = new Command(\"audit\")\n .description(\"Show CRM audit trail — who changed what and when\")\n .option(\"--slug <slug>\", \"Filter by customer slug\")\n .option(\"--actor <actor>\", \"Filter by actor\")\n .option(\"--limit <n>\", \"Number of entries to show (default: 20)\", parseInt)\n .option(\"--tail\", \"Show all new entries (simplified: shows current entries)\")\n .action((opts: { slug?: string; actor?: string; limit?: number; tail?: boolean }) =>\n runAudit(opts, process.env[\"DXCRM_DATA_DIR\"])\n );\n","import { Command } from \"commander\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { MainFactsSchema } from \"../schemas/main-facts.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport matter from \"gray-matter\";\nimport { success, error, warning, info } from \"../ui/colors.js\";\n\nconst RECOVERABLE_DEFAULTS: Record<string, unknown> = {\n tags: [],\n currency: \"EUR\",\n};\n\nexport function applyFix(\n factsPath: string,\n content: string,\n data: Record<string, unknown>\n): { fixed: string[]; content: string } | null {\n const fixed: string[] = [];\n const patched = { ...data };\n\n for (const [field, defaultValue] of Object.entries(RECOVERABLE_DEFAULTS)) {\n if (patched[field] === undefined || patched[field] === null) {\n patched[field] = defaultValue;\n fixed.push(`${field} → ${JSON.stringify(defaultValue)}`);\n }\n }\n\n if (patched[\"updated\"] === undefined && patched[\"created\"]) {\n patched[\"updated\"] = patched[\"created\"];\n fixed.push(`updated → ${String(patched[\"created\"])}`);\n }\n\n if (fixed.length === 0) return null;\n\n const parsed = matter(content);\n const newContent = matter.stringify(parsed.content, patched);\n fs.writeFileSync(factsPath, newContent);\n return { fixed, content: newContent };\n}\n\nexport async function runValidate(opts: { fix?: boolean }, dataDir: string): Promise<void> {\n const customersDir = path.join(dataDir, \"customers\");\n\n if (!fs.existsSync(customersDir)) {\n console.log(warning(\"⚠ No customers directory found.\"));\n return;\n }\n\n const slugs = listCustomerSlugs(dataDir);\n\n let errorCount = 0;\n let fixedCount = 0;\n\n for (const slug of slugs) {\n const factsPath = path.join(customersDir, slug, \"main_facts.md\");\n const interactionsPath = path.join(customersDir, slug, \"interactions.md\");\n\n if (!fs.existsSync(factsPath)) {\n console.log(error(`✗ ${slug}: missing main_facts.md`));\n errorCount++;\n continue;\n }\n\n try {\n let content = fs.readFileSync(factsPath, \"utf-8\") as string;\n const { data } = matter(content);\n\n if (opts.fix) {\n const result = applyFix(factsPath, content, data as Record<string, unknown>);\n if (result) {\n content = result.content;\n fixedCount++;\n console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(\", \")}`));\n }\n }\n\n const { data: refetchedData } = matter(content);\n MainFactsSchema.parse(refetchedData);\n\n if (!fs.existsSync(interactionsPath)) {\n console.log(warning(`⚠ ${slug}: missing interactions.md`));\n } else {\n console.log(success(`✓ ${slug}`));\n }\n } catch (err) {\n console.log(error(`✗ ${slug}: ${(err as Error).message}`));\n errorCount++;\n }\n }\n\n if (opts.fix && fixedCount > 0) {\n console.log(info(`\\n⚙ Fixed ${fixedCount} customer(s).`));\n }\n\n if (errorCount > 0) {\n console.error(error(`\\n${errorCount} error(s) found.`));\n process.exit(1);\n } else {\n console.log(success(\"\\n✓ All customers valid.\"));\n }\n}\n\nexport const validateCommand = new Command(\"validate\")\n .option(\"--fix\", \"Auto-fix recoverable issues\")\n .action(async (opts: { fix?: boolean }) => {\n await runValidate(opts, process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd());\n });\n","export const VERSION = \"0.1.0\";\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const require_chunk = require("./chunk-DakpK96I.cjs");
|
|
2
|
+
const require_write_queue = require("./write-queue-BDolUxfs.cjs");
|
|
3
|
+
let path = require("path");
|
|
4
|
+
path = require_chunk.__toESM(path, 1);
|
|
5
|
+
let fs = require("fs");
|
|
6
|
+
fs = require_chunk.__toESM(fs, 1);
|
|
7
|
+
//#region src/fs/interactions-writer.ts
|
|
8
|
+
var interactions_writer_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
9
|
+
appendInteraction: () => appendInteraction,
|
|
10
|
+
formatInteractionEntry: () => formatInteractionEntry,
|
|
11
|
+
readInteractions: () => readInteractions
|
|
12
|
+
});
|
|
13
|
+
const INTERACTION_SEPARATOR = "---";
|
|
14
|
+
function formatInteractionEntry(entry) {
|
|
15
|
+
const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : ""}`;
|
|
16
|
+
const withLabel = entry.type === "Email" ? "Subject" : "With";
|
|
17
|
+
const nextStepsBlock = entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join("\n") : "- [ ] —";
|
|
18
|
+
return `${header}
|
|
19
|
+
**${withLabel}:** ${entry.with}
|
|
20
|
+
**Summary:** ${entry.summary}
|
|
21
|
+
**Next Steps:**
|
|
22
|
+
${nextStepsBlock}
|
|
23
|
+
**Source:** ${entry.sourceRef}
|
|
24
|
+
**Synced:** ${entry.synced}
|
|
25
|
+
${INTERACTION_SEPARATOR}
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
async function readInteractions(dataDir, slug) {
|
|
29
|
+
const filePath = path.default.join(dataDir, "customers", slug, "interactions.md");
|
|
30
|
+
if (!fs.default.existsSync(filePath)) return "";
|
|
31
|
+
return fs.default.readFileSync(filePath, "utf-8");
|
|
32
|
+
}
|
|
33
|
+
async function appendInteraction(dataDir, slug, entry) {
|
|
34
|
+
const filePath = path.default.join(dataDir, "customers", slug, "interactions.md");
|
|
35
|
+
return require_write_queue.withFileQueue(filePath, async () => {
|
|
36
|
+
const existing = fs.default.existsSync(filePath) ? fs.default.readFileSync(filePath, "utf-8") : "";
|
|
37
|
+
const formatted = formatInteractionEntry(entry);
|
|
38
|
+
let newContent;
|
|
39
|
+
if (existing === "") newContent = formatted;
|
|
40
|
+
else {
|
|
41
|
+
const headerEnd = existing.indexOf("\n\n");
|
|
42
|
+
if (headerEnd > -1) {
|
|
43
|
+
const header = existing.slice(0, headerEnd + 2);
|
|
44
|
+
const body = existing.slice(headerEnd + 2);
|
|
45
|
+
newContent = header + formatted + "\n" + body;
|
|
46
|
+
} else newContent = existing + "\n" + formatted;
|
|
47
|
+
}
|
|
48
|
+
fs.default.writeFileSync(filePath, newContent, "utf-8");
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
Object.defineProperty(exports, "appendInteraction", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: function() {
|
|
55
|
+
return appendInteraction;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(exports, "formatInteractionEntry", {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function() {
|
|
61
|
+
return formatInteractionEntry;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
Object.defineProperty(exports, "interactions_writer_exports", {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
get: function() {
|
|
67
|
+
return interactions_writer_exports;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
Object.defineProperty(exports, "readInteractions", {
|
|
71
|
+
enumerable: true,
|
|
72
|
+
get: function() {
|
|
73
|
+
return readInteractions;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
//# sourceMappingURL=interactions-writer-CrPStUll.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions-writer-CrPStUll.cjs","names":["withFileQueue"],"sources":["../src/fs/interactions-writer.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { InteractionEntry } from \"../schemas/interaction.js\";\nimport { withFileQueue } from \"./write-queue.js\";\n\nconst INTERACTION_SEPARATOR = \"---\";\n\nexport function formatInteractionEntry(entry: InteractionEntry): string {\n const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : \"\"}`;\n const withLabel = entry.type === \"Email\" ? \"Subject\" : \"With\";\n const nextStepsBlock =\n entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join(\"\\n\") : \"- [ ] —\";\n\n return `${header}\n**${withLabel}:** ${entry.with}\n**Summary:** ${entry.summary}\n**Next Steps:**\n${nextStepsBlock}\n**Source:** ${entry.sourceRef}\n**Synced:** ${entry.synced}\n${INTERACTION_SEPARATOR}\n`;\n}\n\nexport async function readInteractions(dataDir: string, slug: string): Promise<string> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n if (!fs.existsSync(filePath)) {\n return \"\";\n }\n return fs.readFileSync(filePath, \"utf-8\");\n}\n\nexport async function appendInteraction(\n dataDir: string,\n slug: string,\n entry: InteractionEntry\n): Promise<void> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n return withFileQueue(filePath, async () => {\n const existing = fs.existsSync(filePath) ? (fs.readFileSync(filePath, \"utf-8\") as string) : \"\";\n\n const formatted = formatInteractionEntry(entry);\n\n let newContent: string;\n if (existing === \"\") {\n newContent = formatted;\n } else {\n const headerEnd = existing.indexOf(\"\\n\\n\");\n if (headerEnd > -1) {\n const header = existing.slice(0, headerEnd + 2);\n const body = existing.slice(headerEnd + 2);\n newContent = header + formatted + \"\\n\" + body;\n } else {\n newContent = existing + \"\\n\" + formatted;\n }\n }\n\n fs.writeFileSync(filePath, newContent, \"utf-8\");\n });\n}\n"],"mappings":";;;;;;;;;;;;AAKA,MAAM,wBAAwB;AAE9B,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,YAAY,MAAM,MAAM,cAAc;CAC9F,MAAM,YAAY,MAAM,SAAS,UAAU,YAAY;CACvD,MAAM,iBACJ,MAAM,UAAU,SAAS,IAAI,MAAM,UAAU,KAAK,MAAM,SAAS,GAAG,EAAE,KAAK,IAAI,IAAI;CAErF,OAAO,GAAG,OAAO;IACf,UAAU,MAAM,MAAM,KAAK;eAChB,MAAM,QAAQ;;EAE3B,eAAe;cACH,MAAM,UAAU;cAChB,MAAM,OAAO;EACzB,sBAAsB;;AAExB;AAEA,eAAsB,iBAAiB,SAAiB,MAA+B;CACrF,MAAM,WAAW,KAAA,QAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,IAAI,CAAC,GAAA,QAAG,WAAW,QAAQ,GACzB,OAAO;CAET,OAAO,GAAA,QAAG,aAAa,UAAU,OAAO;AAC1C;AAEA,eAAsB,kBACpB,SACA,MACA,OACe;CACf,MAAM,WAAW,KAAA,QAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,OAAOA,oBAAAA,cAAc,UAAU,YAAY;EACzC,MAAM,WAAW,GAAA,QAAG,WAAW,QAAQ,IAAK,GAAA,QAAG,aAAa,UAAU,OAAO,IAAe;EAE5F,MAAM,YAAY,uBAAuB,KAAK;EAE9C,IAAI;EACJ,IAAI,aAAa,IACf,aAAa;OACR;GACL,MAAM,YAAY,SAAS,QAAQ,MAAM;GACzC,IAAI,YAAY,IAAI;IAClB,MAAM,SAAS,SAAS,MAAM,GAAG,YAAY,CAAC;IAC9C,MAAM,OAAO,SAAS,MAAM,YAAY,CAAC;IACzC,aAAa,SAAS,YAAY,OAAO;GAC3C,OACE,aAAa,WAAW,OAAO;EAEnC;EAEA,GAAA,QAAG,cAAc,UAAU,YAAY,OAAO;CAChD,CAAC;AACH"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
//#region src/fs/interactions-writer.ts
|
|
6
|
+
var interactions_writer_exports = /* @__PURE__ */ __exportAll({
|
|
7
|
+
appendInteraction: () => appendInteraction,
|
|
8
|
+
formatInteractionEntry: () => formatInteractionEntry,
|
|
9
|
+
readInteractions: () => readInteractions
|
|
10
|
+
});
|
|
11
|
+
const INTERACTION_SEPARATOR = "---";
|
|
12
|
+
function formatInteractionEntry(entry) {
|
|
13
|
+
const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : ""}`;
|
|
14
|
+
const withLabel = entry.type === "Email" ? "Subject" : "With";
|
|
15
|
+
const nextStepsBlock = entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join("\n") : "- [ ] —";
|
|
16
|
+
return `${header}
|
|
17
|
+
**${withLabel}:** ${entry.with}
|
|
18
|
+
**Summary:** ${entry.summary}
|
|
19
|
+
**Next Steps:**
|
|
20
|
+
${nextStepsBlock}
|
|
21
|
+
**Source:** ${entry.sourceRef}
|
|
22
|
+
**Synced:** ${entry.synced}
|
|
23
|
+
${INTERACTION_SEPARATOR}
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
async function readInteractions(dataDir, slug) {
|
|
27
|
+
const filePath = path.join(dataDir, "customers", slug, "interactions.md");
|
|
28
|
+
if (!fs.existsSync(filePath)) return "";
|
|
29
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
async function appendInteraction(dataDir, slug, entry) {
|
|
32
|
+
const filePath = path.join(dataDir, "customers", slug, "interactions.md");
|
|
33
|
+
return withFileQueue(filePath, async () => {
|
|
34
|
+
const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
|
|
35
|
+
const formatted = formatInteractionEntry(entry);
|
|
36
|
+
let newContent;
|
|
37
|
+
if (existing === "") newContent = formatted;
|
|
38
|
+
else {
|
|
39
|
+
const headerEnd = existing.indexOf("\n\n");
|
|
40
|
+
if (headerEnd > -1) {
|
|
41
|
+
const header = existing.slice(0, headerEnd + 2);
|
|
42
|
+
const body = existing.slice(headerEnd + 2);
|
|
43
|
+
newContent = header + formatted + "\n" + body;
|
|
44
|
+
} else newContent = existing + "\n" + formatted;
|
|
45
|
+
}
|
|
46
|
+
fs.writeFileSync(filePath, newContent, "utf-8");
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { readInteractions as i, formatInteractionEntry as n, interactions_writer_exports as r, appendInteraction as t };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=interactions-writer-DO3KcSR3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions-writer-DO3KcSR3.js","names":[],"sources":["../src/fs/interactions-writer.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { InteractionEntry } from \"../schemas/interaction.js\";\nimport { withFileQueue } from \"./write-queue.js\";\n\nconst INTERACTION_SEPARATOR = \"---\";\n\nexport function formatInteractionEntry(entry: InteractionEntry): string {\n const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : \"\"}`;\n const withLabel = entry.type === \"Email\" ? \"Subject\" : \"With\";\n const nextStepsBlock =\n entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join(\"\\n\") : \"- [ ] —\";\n\n return `${header}\n**${withLabel}:** ${entry.with}\n**Summary:** ${entry.summary}\n**Next Steps:**\n${nextStepsBlock}\n**Source:** ${entry.sourceRef}\n**Synced:** ${entry.synced}\n${INTERACTION_SEPARATOR}\n`;\n}\n\nexport async function readInteractions(dataDir: string, slug: string): Promise<string> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n if (!fs.existsSync(filePath)) {\n return \"\";\n }\n return fs.readFileSync(filePath, \"utf-8\");\n}\n\nexport async function appendInteraction(\n dataDir: string,\n slug: string,\n entry: InteractionEntry\n): Promise<void> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n return withFileQueue(filePath, async () => {\n const existing = fs.existsSync(filePath) ? (fs.readFileSync(filePath, \"utf-8\") as string) : \"\";\n\n const formatted = formatInteractionEntry(entry);\n\n let newContent: string;\n if (existing === \"\") {\n newContent = formatted;\n } else {\n const headerEnd = existing.indexOf(\"\\n\\n\");\n if (headerEnd > -1) {\n const header = existing.slice(0, headerEnd + 2);\n const body = existing.slice(headerEnd + 2);\n newContent = header + formatted + \"\\n\" + body;\n } else {\n newContent = existing + \"\\n\" + formatted;\n }\n }\n\n fs.writeFileSync(filePath, newContent, \"utf-8\");\n });\n}\n"],"mappings":";;;;;;;;;;AAKA,MAAM,wBAAwB;AAE9B,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,YAAY,MAAM,MAAM,cAAc;CAC9F,MAAM,YAAY,MAAM,SAAS,UAAU,YAAY;CACvD,MAAM,iBACJ,MAAM,UAAU,SAAS,IAAI,MAAM,UAAU,KAAK,MAAM,SAAS,GAAG,EAAE,KAAK,IAAI,IAAI;CAErF,OAAO,GAAG,OAAO;IACf,UAAU,MAAM,MAAM,KAAK;eAChB,MAAM,QAAQ;;EAE3B,eAAe;cACH,MAAM,UAAU;cAChB,MAAM,OAAO;EACzB,sBAAsB;;AAExB;AAEA,eAAsB,iBAAiB,SAAiB,MAA+B;CACrF,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,IAAI,CAAC,GAAG,WAAW,QAAQ,GACzB,OAAO;CAET,OAAO,GAAG,aAAa,UAAU,OAAO;AAC1C;AAEA,eAAsB,kBACpB,SACA,MACA,OACe;CACf,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,OAAO,cAAc,UAAU,YAAY;EACzC,MAAM,WAAW,GAAG,WAAW,QAAQ,IAAK,GAAG,aAAa,UAAU,OAAO,IAAe;EAE5F,MAAM,YAAY,uBAAuB,KAAK;EAE9C,IAAI;EACJ,IAAI,aAAa,IACf,aAAa;OACR;GACL,MAAM,YAAY,SAAS,QAAQ,MAAM;GACzC,IAAI,YAAY,IAAI;IAClB,MAAM,SAAS,SAAS,MAAM,GAAG,YAAY,CAAC;IAC9C,MAAM,OAAO,SAAS,MAAM,YAAY,CAAC;IACzC,aAAa,SAAS,YAAY,OAAO;GAC3C,OACE,aAAa,WAAW,OAAO;EAEnC;EAEA,GAAG,cAAc,UAAU,YAAY,OAAO;CAChD,CAAC;AACH"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
//#region src/fs/interactions-writer.ts
|
|
5
|
+
const INTERACTION_SEPARATOR = "---";
|
|
6
|
+
function formatInteractionEntry(entry) {
|
|
7
|
+
const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : ""}`;
|
|
8
|
+
const withLabel = entry.type === "Email" ? "Subject" : "With";
|
|
9
|
+
const nextStepsBlock = entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join("\n") : "- [ ] —";
|
|
10
|
+
return `${header}
|
|
11
|
+
**${withLabel}:** ${entry.with}
|
|
12
|
+
**Summary:** ${entry.summary}
|
|
13
|
+
**Next Steps:**
|
|
14
|
+
${nextStepsBlock}
|
|
15
|
+
**Source:** ${entry.sourceRef}
|
|
16
|
+
**Synced:** ${entry.synced}
|
|
17
|
+
${INTERACTION_SEPARATOR}
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
async function readInteractions(dataDir, slug) {
|
|
21
|
+
const filePath = path.join(dataDir, "customers", slug, "interactions.md");
|
|
22
|
+
if (!fs.existsSync(filePath)) return "";
|
|
23
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
24
|
+
}
|
|
25
|
+
async function appendInteraction(dataDir, slug, entry) {
|
|
26
|
+
const filePath = path.join(dataDir, "customers", slug, "interactions.md");
|
|
27
|
+
return withFileQueue(filePath, async () => {
|
|
28
|
+
const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
|
|
29
|
+
const formatted = formatInteractionEntry(entry);
|
|
30
|
+
let newContent;
|
|
31
|
+
if (existing === "") newContent = formatted;
|
|
32
|
+
else {
|
|
33
|
+
const headerEnd = existing.indexOf("\n\n");
|
|
34
|
+
if (headerEnd > -1) {
|
|
35
|
+
const header = existing.slice(0, headerEnd + 2);
|
|
36
|
+
const body = existing.slice(headerEnd + 2);
|
|
37
|
+
newContent = header + formatted + "\n" + body;
|
|
38
|
+
} else newContent = existing + "\n" + formatted;
|
|
39
|
+
}
|
|
40
|
+
fs.writeFileSync(filePath, newContent, "utf-8");
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { formatInteractionEntry as n, readInteractions as r, appendInteraction as t };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=interactions-writer-SLHnoEeE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions-writer-SLHnoEeE.js","names":[],"sources":["../src/fs/interactions-writer.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { InteractionEntry } from \"../schemas/interaction.js\";\nimport { withFileQueue } from \"./write-queue.js\";\n\nconst INTERACTION_SEPARATOR = \"---\";\n\nexport function formatInteractionEntry(entry: InteractionEntry): string {\n const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : \"\"}`;\n const withLabel = entry.type === \"Email\" ? \"Subject\" : \"With\";\n const nextStepsBlock =\n entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join(\"\\n\") : \"- [ ] —\";\n\n return `${header}\n**${withLabel}:** ${entry.with}\n**Summary:** ${entry.summary}\n**Next Steps:**\n${nextStepsBlock}\n**Source:** ${entry.sourceRef}\n**Synced:** ${entry.synced}\n${INTERACTION_SEPARATOR}\n`;\n}\n\nexport async function readInteractions(dataDir: string, slug: string): Promise<string> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n if (!fs.existsSync(filePath)) {\n return \"\";\n }\n return fs.readFileSync(filePath, \"utf-8\");\n}\n\nexport async function appendInteraction(\n dataDir: string,\n slug: string,\n entry: InteractionEntry\n): Promise<void> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n return withFileQueue(filePath, async () => {\n const existing = fs.existsSync(filePath) ? (fs.readFileSync(filePath, \"utf-8\") as string) : \"\";\n\n const formatted = formatInteractionEntry(entry);\n\n let newContent: string;\n if (existing === \"\") {\n newContent = formatted;\n } else {\n const headerEnd = existing.indexOf(\"\\n\\n\");\n if (headerEnd > -1) {\n const header = existing.slice(0, headerEnd + 2);\n const body = existing.slice(headerEnd + 2);\n newContent = header + formatted + \"\\n\" + body;\n } else {\n newContent = existing + \"\\n\" + formatted;\n }\n }\n\n fs.writeFileSync(filePath, newContent, \"utf-8\");\n });\n}\n"],"mappings":";;;;AAKA,MAAM,wBAAwB;AAE9B,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,YAAY,MAAM,MAAM,cAAc;CAC9F,MAAM,YAAY,MAAM,SAAS,UAAU,YAAY;CACvD,MAAM,iBACJ,MAAM,UAAU,SAAS,IAAI,MAAM,UAAU,KAAK,MAAM,SAAS,GAAG,EAAE,KAAK,IAAI,IAAI;CAErF,OAAO,GAAG,OAAO;IACf,UAAU,MAAM,MAAM,KAAK;eAChB,MAAM,QAAQ;;EAE3B,eAAe;cACH,MAAM,UAAU;cAChB,MAAM,OAAO;EACzB,sBAAsB;;AAExB;AAEA,eAAsB,iBAAiB,SAAiB,MAA+B;CACrF,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,IAAI,CAAC,GAAG,WAAW,QAAQ,GACzB,OAAO;CAET,OAAO,GAAG,aAAa,UAAU,OAAO;AAC1C;AAEA,eAAsB,kBACpB,SACA,MACA,OACe;CACf,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,OAAO,cAAc,UAAU,YAAY;EACzC,MAAM,WAAW,GAAG,WAAW,QAAQ,IAAK,GAAG,aAAa,UAAU,OAAO,IAAe;EAE5F,MAAM,YAAY,uBAAuB,KAAK;EAE9C,IAAI;EACJ,IAAI,aAAa,IACf,aAAa;OACR;GACL,MAAM,YAAY,SAAS,QAAQ,MAAM;GACzC,IAAI,YAAY,IAAI;IAClB,MAAM,SAAS,SAAS,MAAM,GAAG,YAAY,CAAC;IAC9C,MAAM,OAAO,SAAS,MAAM,YAAY,CAAC;IACzC,aAAa,SAAS,YAAY,OAAO;GAC3C,OACE,aAAa,WAAW,OAAO;EAEnC;EAEA,GAAG,cAAc,UAAU,YAAY,OAAO;CAChD,CAAC;AACH"}
|