@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.
Files changed (62) hide show
  1. package/README.md +16 -16
  2. package/changelog.json +22 -0
  3. package/dist/admin/admin-files.json +7 -7
  4. package/dist/admin/assets/{chartsImpl-aBuZ1X4W.js → chartsImpl-zjsXDhuy.js} +1 -1
  5. package/dist/admin/assets/firebase-C3h9mF8O.js +2 -0
  6. package/dist/admin/assets/{gitJson-DzX3eZ2P.js → gitJson-nrOYgX0x.js} +1 -1
  7. package/dist/admin/assets/{index-DLy5RpPl.js → index-0ejjkW0z.js} +6 -6
  8. package/dist/admin/assets/{lucide-react.min-BgcmukkH.js → lucide-react.min-CI5dCsSm.js} +1 -1
  9. package/dist/admin/assets/{sdk-DtP9zqdi.js → sdk-mepKXtVl.js} +135 -120
  10. package/dist/admin/index.html +1 -1
  11. package/dist/agent/agentcrm.mjs +159 -74
  12. package/dist/agent/chunks/api-BEl_EKwf.mjs +79 -0
  13. package/dist/agent/chunks/{automations-DwWruxmu.mjs → automations-BqY8EwfJ.mjs} +3 -3
  14. package/dist/agent/chunks/{backup-W3CjgkAJ.mjs → backup-CO0EzdF_.mjs} +3 -3
  15. package/dist/agent/chunks/{compact-BGHI92tm.mjs → compact-qF5t42ko.mjs} +3 -3
  16. package/dist/agent/chunks/{exportCsv-C6e6XEmB.mjs → exportCsv-C-fIHLm1.mjs} +2 -2
  17. package/dist/agent/chunks/{extCheck-GgHG1dYB.mjs → extCheck-BcbUc7eB.mjs} +4 -4
  18. package/dist/agent/chunks/{files-D1daDgY0.mjs → files-C4YONVqQ.mjs} +2 -2
  19. package/dist/agent/chunks/{firebase-DWR0K1OC.mjs → firebase-Bknru2pE.mjs} +230 -53
  20. package/dist/agent/chunks/firebaseCache-sK4jA0ru.mjs +39 -0
  21. package/dist/agent/chunks/{firebaseRules-iori-s7U.mjs → firebaseRules-Jq85MBBN.mjs} +14 -3
  22. package/dist/agent/chunks/{forms-BfuWaQjA.mjs → forms-DJDop3XY.mjs} +2 -2
  23. package/dist/agent/chunks/{hosting-Dnn1k3cV.mjs → hosting-C_UDyMkm.mjs} +1 -1
  24. package/dist/agent/chunks/{importCsv-LVmMTaWU.mjs → importCsv-XjQJ9QIR.mjs} +2 -2
  25. package/dist/agent/chunks/{index-DtCezG4R.mjs → index-DWecFbTi.mjs} +1 -1
  26. package/dist/agent/chunks/{install-Bp-CwDVC.mjs → install-D1lgtRIH.mjs} +4 -4
  27. package/dist/agent/chunks/{loader-MPD9iAvh.mjs → loader-Cv0UJf6b.mjs} +11 -11
  28. package/dist/agent/chunks/{migrate-CsClnnN8.mjs → migrate-Cc_8MHZv.mjs} +1 -1
  29. package/dist/agent/chunks/{pipelines-BAKpPk1w.mjs → pipelines-DiJ2dLqQ.mjs} +3 -3
  30. package/dist/agent/chunks/{records-DcHFelq5.mjs → records-CCTxxMWF.mjs} +1 -1
  31. package/dist/agent/chunks/{registry-COfJrSmg.mjs → registry-ClzNZv9Z.mjs} +10 -10
  32. package/dist/agent/chunks/{reports-BACHGccj.mjs → reports-WlI_A5Nr.mjs} +3 -3
  33. package/dist/agent/chunks/{runtime-C0Xf0Axi.mjs → runtime-BAF5vU5D.mjs} +17 -17
  34. package/dist/agent/chunks/{schema-C4lSslXv.mjs → schema-DOnnH2zL.mjs} +3 -3
  35. package/dist/agent/chunks/schemaApply-DKHipylx.mjs +164 -0
  36. package/dist/agent/chunks/{sdk-CYgNyuoK.mjs → sdk-NYUHv7WG.mjs} +493 -214
  37. package/dist/agent/chunks/{seed-6MRmQQBR.mjs → seed-Bb26Zsni.mjs} +2 -2
  38. package/dist/agent/chunks/{server-DC3t8r30.mjs → server-Bch4TQon.mjs} +3 -3
  39. package/dist/agent/chunks/{standardObjects-CheqfDqa.mjs → standardObjects-vrmqIVLH.mjs} +1 -1
  40. package/dist/agent/chunks/{stats-BfuLWhVV.mjs → stats-DfmDP3tE.mjs} +3 -3
  41. package/dist/agent/chunks/{tools-iSH-yMpl.mjs → tools-CCk24tdh.mjs} +9 -9
  42. package/dist/agent/chunks/{views-DH1n9Lrt.mjs → views-BbhmQO3n.mjs} +4 -4
  43. package/dist/version.json +1 -1
  44. package/package.json +1 -1
  45. package/plugin/.claude-plugin/plugin.json +1 -1
  46. package/plugin/skills/agentcrm-admin/SKILL.md +67 -67
  47. package/plugin/skills/agentcrm-admin/references/records.md +5 -5
  48. package/plugin/skills/agentcrm-admin/references/schema.md +19 -19
  49. package/plugin/skills/agentcrm-extensions/SKILL.md +8 -8
  50. package/plugin/skills/agentcrm-extensions/references/module-recipes.md +2 -2
  51. package/plugin/skills/agentcrm-extensions/references/testing.md +14 -14
  52. package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +3 -3
  53. package/plugin/skills/agentcrm-install/SKILL.md +13 -13
  54. package/plugin/skills/agentcrm-install/references/firebase.md +1 -1
  55. package/plugin/skills/agentcrm-install/references/github.md +1 -1
  56. package/plugin/skills/agentcrm-install/references/mcp.md +2 -2
  57. package/plugin/skills/agentcrm-install/references/plans.md +1 -1
  58. package/plugin/skills/agentcrm-install/references/s3.md +1 -1
  59. package/plugin/skills/agentcrm-manage/SKILL.md +15 -15
  60. package/plugin/skills/agentcrm-sales/SKILL.md +18 -18
  61. package/dist/admin/assets/firebase-BG1GpyBB.js +0 -2
  62. package/dist/agent/chunks/api-Dwb4xz1k.mjs +0 -27
@@ -57,9 +57,9 @@ Variables: `--acc-50` … `--acc-950` (accent scale), `--srf-50` … `--srf-950`
57
57
 
58
58
  ```bash
59
59
  npm run build
60
- npx -y @fleox-agent-crm/agentcrm@0.3.3 ext check . --json
61
- npx -y @fleox-agent-crm/agentcrm@0.3.3 ext install . --site acme --yes --json
62
- npx -y @fleox-agent-crm/agentcrm@0.3.3 appearance preset acme-brand --site acme --json
60
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 ext check . --json
61
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 ext install . --site acme --yes --json
62
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 appearance preset acme-brand --site acme --json
63
63
  ```
64
64
 
65
65
  `ext check` prints the resolved values (`data.theme.appearance`) and the CSS size. `appearance preset` prints the before / after plan; add `--yes` to apply. Open the admin to look at it (light and dark, a table and a record page).
@@ -4,7 +4,7 @@ description: Install a new AgentCRM (static, AI-drivable CRM) for the user - ask
4
4
  license: PolyForm-Noncommercial-1.0.0
5
5
  compatibility: Requires Node.js 20+ and network access to the chosen storage. Works in Claude Code and any agent that can run shell commands.
6
6
  metadata:
7
- version: "0.3.3"
7
+ version: "0.5.0"
8
8
  repository: "https://github.com/fleox/agentcrm"
9
9
  allowed-tools: Bash Read Write
10
10
  ---
@@ -15,13 +15,13 @@ AgentCRM is a HubSpot / Twenty-style CRM (companies, people, deals, pipelines, a
15
15
 
16
16
  **Language:** talk to the user in their language; keep commands, files and plans in English.
17
17
 
18
- Every command is `npx -y @fleox-agent-crm/agentcrm@0.3.3 <command> --json` (Node.js 20+). Each prints ONE JSON object: `{"ok": true, "data": ...}` or `{"ok": false, "error": {"code", "message", "hint"}}`. When `ok` is false, read `error.hint` and act on it. Exit code 2 = a usage error in your command.
18
+ Every command is `npx -y @fleox-agent-crm/agentcrm@0.5.0 <command> --json` (Node.js 20+). Each prints ONE JSON object: `{"ok": true, "data": ...}` or `{"ok": false, "error": {"code", "message", "hint"}}`. When `ok` is false, read `error.hint` and act on it. Exit code 2 = a usage error in your command.
19
19
 
20
20
  ## 1. Start with status and options
21
21
 
22
22
  ```bash
23
- npx -y @fleox-agent-crm/agentcrm@0.3.3 status --json
24
- npx -y @fleox-agent-crm/agentcrm@0.3.3 options --json
23
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 status --json
24
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 options --json
25
25
  ```
26
26
 
27
27
  `status` shows CRMs this computer already manages (maybe the user wants `agentcrm-manage` instead). `options` lists backends, data locations, hostings, credential types and the plan format.
@@ -36,7 +36,7 @@ The CRM holds personal data (contacts, emails, phone numbers). Ask, in this orde
36
36
  - a **folder on this computer** - single computer, no account. Advise backing it up.
37
37
  2. **Firebase** (backend `firebase`) - real-time teams with logins and per-user roles. See references/firebase.md.
38
38
  3. **A private git repo as readable JSON** (backend `git-json`) - readable history, but deleted records stay in the git history: warn the user.
39
- 4. **This browser only** - for trying it: `npx -y @fleox-agent-crm/agentcrm@0.3.3 serve --json`, then "This browser" in the wizard. The CLI can't reach it.
39
+ 4. **This browser only** - for trying it: `npx -y @fleox-agent-crm/agentcrm@0.5.0 serve --json`, then "This browser" in the wizard. The CLI can't reach it.
40
40
 
41
41
  Encryption: the journal is encrypted with AES-256-GCM by default. A passphrase is generated at install and stored only on this computer. Never offer to turn it off unless the user insists and the location is strictly private.
42
42
 
@@ -54,15 +54,15 @@ HTTPS is required: browsers only allow the admin's request signing and encryptio
54
54
 
55
55
  ## 4. Credentials - never in the chat
56
56
 
57
- Secrets (keys, tokens, passwords, passphrases) are NEVER typed into the conversation and never written in a plan. The user stores each one in their own terminal; in Claude Code they type `! npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials set s3:main` (hidden prompt). Alternatives that keep secrets out of the chat:
57
+ Secrets (keys, tokens, passwords, passphrases) are NEVER typed into the conversation and never written in a plan. The user stores each one in their own terminal; in Claude Code they type `! npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials set s3:main` (hidden prompt). Alternatives that keep secrets out of the chat:
58
58
 
59
59
  - `--from-env KEY_ID,SECRET` - variables the user already exported (CI, `.env`).
60
60
  - `--from-aws-profile <profile>` - an existing aws CLI profile (s3).
61
61
  - `--from-gh` - the token of the signed-in GitHub CLI (github).
62
62
 
63
63
  ```bash
64
- npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials list --json
65
- npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials types --json
64
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials list --json
65
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials types --json
66
66
  ```
67
67
 
68
68
  How to create each key with least privilege: references/s3.md, references/github.md, references/firebase.md. One account can serve several CRMs (`s3:main` for both the data bucket and the hosting bucket is fine).
@@ -89,8 +89,8 @@ Write `plan.json` (no secrets, only account ids):
89
89
  More examples (GitHub repo data + GitHub Pages, local folder, Firebase): references/plans.md. `owner` becomes the first CRM admin, and the CLI acts as that user. `demo: true` adds a realistic sample dataset - offer it for a first look, not for a production CRM.
90
90
 
91
91
  ```bash
92
- npx -y @fleox-agent-crm/agentcrm@0.3.3 install --plan plan.json --dry-run --json
93
- npx -y @fleox-agent-crm/agentcrm@0.3.3 install --plan plan.json --json
92
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 install --plan plan.json --dry-run --json
93
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 install --plan plan.json --json
94
94
  ```
95
95
 
96
96
  The dry run checks every access and writes nothing. Fix `check-failed` errors with their hint (permissions, names, CORS) before installing. An existing dataset in the same place is kept; only what's missing is seeded.
@@ -99,16 +99,16 @@ The dry run checks every access and writes nothing. Fix `check-failed` errors wi
99
99
 
100
100
  When the result has `savePassphrase`, stop and do it with the user before anything else:
101
101
 
102
- 1. `npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials copy passphrase:<alias> --json` puts it on the clipboard (never print it).
102
+ 1. `npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials copy passphrase:<alias> --json` puts it on the clipboard (never print it).
103
103
  2. The user pastes it into their password manager now.
104
- 3. The user proves it: in their own terminal, `! npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials verify passphrase:<alias>`, pasting FROM the password manager. It must say "verified".
104
+ 3. The user proves it: in their own terminal, `! npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials verify passphrase:<alias>`, pasting FROM the password manager. It must say "verified".
105
105
 
106
106
  Without the passphrase nobody can read the data, ever.
107
107
 
108
108
  ## 7. Verify
109
109
 
110
110
  ```bash
111
- npx -y @fleox-agent-crm/agentcrm@0.3.3 doctor --site <alias> --json
111
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 doctor --site <alias> --json
112
112
  ```
113
113
 
114
114
  Every failing check has a `fix`. The most common one on buckets is CORS: the result prints the exact JSON rule for the data bucket - help the user apply it (references/s3.md). Then give the user the admin URL (`data.adminUrl` of the install) and explain: each new browser asks once for the storage keys and the passphrase, which stay in that browser.
@@ -3,7 +3,7 @@
3
3
  1. Create a Firebase project (console.firebase.google.com), add a Web app and copy its config (apiKey, authDomain, projectId, appId...). The web apiKey is public by design.
4
4
  2. Enable Authentication → Sign-in method → Email/Password (and Google if wanted).
5
5
  3. Create Firestore (production mode) and publish the AgentCRM security rules (see docs/firebase.md in the repository).
6
- 4. Create the first admin account (Authentication → Users → Add user). The user stores its login: `! npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials set firebase:<name>` (email + password at hidden prompts).
6
+ 4. Create the first admin account (Authentication → Users → Add user). The user stores its login: `! npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials set firebase:<name>` (email + password at hidden prompts).
7
7
  5. Plan:
8
8
 
9
9
  ```json
@@ -7,7 +7,7 @@ Fine-grained personal access token: https://github.com/settings/personal-access-
7
7
  - Repository access: only the data repository (PRIVATE) and, if used, the admin hosting repository.
8
8
  - Permissions: Contents read and write; Metadata read-only; Pages read and write (optional, lets the CLI enable Pages).
9
9
 
10
- The user stores it: `! npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials set github:<login>`, or reuses the GitHub CLI login: `npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials set github:<login> --from-gh --json`.
10
+ The user stores it: `! npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials set github:<login>`, or reuses the GitHub CLI login: `npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials set github:<login> --from-gh --json`.
11
11
 
12
12
  GitLab: project → Settings → Access tokens, scope `api`, role Developer; store as `gitlab:<name>`.
13
13
 
@@ -5,13 +5,13 @@
5
5
  Claude Code:
6
6
 
7
7
  ```bash
8
- claude mcp add agentcrm -- npx -y @fleox-agent-crm/agentcrm@0.3.3 mcp --site <alias>
8
+ claude mcp add agentcrm -- npx -y @fleox-agent-crm/agentcrm@0.5.0 mcp --site <alias>
9
9
  ```
10
10
 
11
11
  Claude Desktop (`claude_desktop_config.json`) and Cursor (`.cursor/mcp.json`):
12
12
 
13
13
  ```json
14
- { "mcpServers": { "agentcrm": { "command": "npx", "args": ["-y", "@fleox-agent-crm/agentcrm@0.3.3", "mcp", "--site", "<alias>"] } } }
14
+ { "mcpServers": { "agentcrm": { "command": "npx", "args": ["-y", "@fleox-agent-crm/agentcrm@0.5.0", "mcp", "--site", "<alias>"] } } }
15
15
  ```
16
16
 
17
17
  The server uses the credentials of this computer (`~/.agentcrm`) and acts as the site's CLI user.
@@ -23,7 +23,7 @@
23
23
  }
24
24
  ```
25
25
 
26
- Use it from the browser with `npx -y @fleox-agent-crm/agentcrm@0.3.3 serve --json` and the folder picker.
26
+ Use it from the browser with `npx -y @fleox-agent-crm/agentcrm@0.5.0 serve --json` and the folder picker.
27
27
 
28
28
  ## git-json in a private repo
29
29
 
@@ -4,7 +4,7 @@ Use TWO buckets: a PRIVATE one for the data (journal backend) and a public one f
4
4
 
5
5
  ## Access key (least privilege)
6
6
 
7
- - **AWS**: IAM user with a policy on both buckets: `s3:GetObject`, `s3:PutObject`, `s3:DeleteObject` on `arn:aws:s3:::<bucket>/*` and `s3:ListBucket` on `arn:aws:s3:::<bucket>`. Store it: `! npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials set s3:main`, or import a profile with `--from-aws-profile <name>`.
7
+ - **AWS**: IAM user with a policy on both buckets: `s3:GetObject`, `s3:PutObject`, `s3:DeleteObject` on `arn:aws:s3:::<bucket>/*` and `s3:ListBucket` on `arn:aws:s3:::<bucket>`. Store it: `! npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials set s3:main`, or import a profile with `--from-aws-profile <name>`.
8
8
  - **Cloudflare R2**: R2 → Manage API tokens → Object Read & Write, scoped to the buckets. Endpoint `https://<account-id>.r2.cloudflarestorage.com`, region `auto`.
9
9
  - **OVHcloud**: Public Cloud → Object Storage → S3 users; endpoint `https://s3.<region>.io.cloud.ovh.net`. Set `publicRead: true` on the hosting bucket.
10
10
  - **Scaleway**: endpoint `https://s3.<region>.scw.cloud`.
@@ -4,7 +4,7 @@ description: Check, repair and update existing AgentCRM CRMs - list the CRMs thi
4
4
  license: PolyForm-Noncommercial-1.0.0
5
5
  compatibility: Requires Node.js 20+.
6
6
  metadata:
7
- version: "0.3.3"
7
+ version: "0.5.0"
8
8
  repository: "https://github.com/fleox/agentcrm"
9
9
  allowed-tools: Bash Read Write
10
10
  ---
@@ -15,12 +15,12 @@ This skill covers the CRMs themselves (registry, health, updates, maintenance).
15
15
 
16
16
  **Language:** talk to the user in their language; keep commands and files in English.
17
17
 
18
- Every command is `npx -y @fleox-agent-crm/agentcrm@0.3.3 <command> --json` (Node.js 20+); read `error.hint` whenever `ok` is false.
18
+ Every command is `npx -y @fleox-agent-crm/agentcrm@0.5.0 <command> --json` (Node.js 20+); read `error.hint` whenever `ok` is false.
19
19
 
20
20
  ## Always start with status
21
21
 
22
22
  ```bash
23
- npx -y @fleox-agent-crm/agentcrm@0.3.3 status --json
23
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 status --json
24
24
  ```
25
25
 
26
26
  - `data.tool.updateAvailable: true` -> tell the user AgentCRM `data.tool.latest` exists and offer to update the skills first (Claude Code: `/plugin marketplace update agentcrm`, then `/reload-plugins`).
@@ -32,8 +32,8 @@ npx -y @fleox-agent-crm/agentcrm@0.3.3 status --json
32
32
  ## Which CRM?
33
33
 
34
34
  ```bash
35
- npx -y @fleox-agent-crm/agentcrm@0.3.3 site list --json
36
- npx -y @fleox-agent-crm/agentcrm@0.3.3 site show <alias> --json
35
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 site list --json
36
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 site show <alias> --json
37
37
  ```
38
38
 
39
39
  Commands take `--site <alias>`; always pass it. Without it the tool uses `AGENTCRM_SITE`, the folder's `agentcrm.json` (`{ "site": "<alias>" }`), the only site, or the default chosen with `site use <alias>` - otherwise it fails with `site-required`: ask the user which CRM. Say which CRM you are working on before changing anything.
@@ -43,12 +43,12 @@ Registry commands: `site use <alias>`, `site rename <from> <to>`, `site forget <
43
43
  ## Register a CRM installed elsewhere
44
44
 
45
45
  ```bash
46
- npx -y @fleox-agent-crm/agentcrm@0.3.3 site add <alias> --admin-url https://crm.acme.com/admin/ --data-credential s3:main --passphrase-credential passphrase:acme --hosting-credential s3:main --json
46
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 site add <alias> --admin-url https://crm.acme.com/admin/ --data-credential s3:main --passphrase-credential passphrase:acme --hosting-credential s3:main --json
47
47
  ```
48
48
 
49
49
  - It reads the admin's public `config.js`, opens the data (proving the credentials) and reads the hosting from the dataset.
50
50
  - `--data-credential`: the data location key (journal), the git token (git-json) or the Firebase login.
51
- - `--passphrase-credential`: encrypted journals. The user stores the passphrase from their password manager: `! npx -y @fleox-agent-crm/agentcrm@0.3.3 credentials set passphrase:<alias>`.
51
+ - `--passphrase-credential`: encrypted journals. The user stores the passphrase from their password manager: `! npx -y @fleox-agent-crm/agentcrm@0.5.0 credentials set passphrase:<alias>`.
52
52
  - `--user <email>`: the CRM user the CLI acts as (default: the first admin).
53
53
  - A CRM in a local folder without a hosted admin: `site add <alias> --runtime @config.json --data-path /path/to/folder`.
54
54
  - `warnings` lists what is still missing; fix later with `site credentials <alias> --hosting-credential <account>` (`""` removes one).
@@ -57,7 +57,7 @@ npx -y @fleox-agent-crm/agentcrm@0.3.3 site add <alias> --admin-url https://crm.
57
57
  ## Health check
58
58
 
59
59
  ```bash
60
- npx -y @fleox-agent-crm/agentcrm@0.3.3 doctor --site <alias> --json
60
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 doctor --site <alias> --json
61
61
  ```
62
62
 
63
63
  `data.checks[]` has `id`, `status` (ok / warn / fail / skip), `message` and, for problems, `fix`. Exit code 1 when a check fails. Walk the user through each fix, most important first:
@@ -75,8 +75,8 @@ Details of every check: references/doctor.md.
75
75
  ## Update a hosted admin
76
76
 
77
77
  ```bash
78
- npx -y @fleox-agent-crm/agentcrm@0.3.3 deploy-admin --site <alias> --json
79
- npx -y @fleox-agent-crm/agentcrm@0.3.3 deploy-admin --site <alias> --yes --json
78
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 deploy-admin --site <alias> --json
79
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 deploy-admin --site <alias> --yes --json
80
80
  ```
81
81
 
82
82
  Without `--yes` it prints the plan (`needsConfirmation: true`, versions, file count): show it, ask, then re-run with `--yes`. `--all` covers every CRM with a hosting. It refuses downgrades and admins that store a newer data format. GitHub / GitLab Pages need a minute before `doctor` sees the new version.
@@ -86,8 +86,8 @@ Without `--yes` it prints the plan (`needsConfirmation: true`, versions, file co
86
86
  Deleted records stay restorable until compaction. To erase them physically and shrink the journal:
87
87
 
88
88
  ```bash
89
- npx -y @fleox-agent-crm/agentcrm@0.3.3 compact --site <alias> --json
90
- npx -y @fleox-agent-crm/agentcrm@0.3.3 compact --site <alias> --yes --json
89
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 compact --site <alias> --json
90
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 compact --site <alias> --yes --json
91
91
  ```
92
92
 
93
93
  Show the plan (records purged) and confirm first: it can't be undone. Run it from one place at a time.
@@ -97,12 +97,12 @@ Show the plan (records purged) and confirm first: it can't be undone. Run it fro
97
97
  Scheduled / inactivity automations and lead form ingestion run when the admin is open, or from a cron. The recommended cron is a GitHub Actions workflow in a private repo: references/cron.md. Locally:
98
98
 
99
99
  ```bash
100
- npx -y @fleox-agent-crm/agentcrm@0.3.3 automations run --site <alias> --yes --json
101
- npx -y @fleox-agent-crm/agentcrm@0.3.3 forms ingest --site <alias> --yes --json
100
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 automations run --site <alias> --yes --json
101
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 forms ingest --site <alias> --yes --json
102
102
  ```
103
103
 
104
104
  ## Overview of one CRM
105
105
 
106
106
  ```bash
107
- npx -y @fleox-agent-crm/agentcrm@0.3.3 stats --site <alias> --json
107
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 stats --site <alias> --json
108
108
  ```
@@ -4,7 +4,7 @@ description: Sales workflows on an AgentCRM - pipeline review and forecast, stal
4
4
  license: PolyForm-Noncommercial-1.0.0
5
5
  compatibility: Requires Node.js 20+. Web search / fetch tools help for enrichment.
6
6
  metadata:
7
- version: "0.3.3"
7
+ version: "0.5.0"
8
8
  repository: "https://github.com/fleox/agentcrm"
9
9
  allowed-tools: Bash Read Write WebSearch WebFetch
10
10
  ---
@@ -15,7 +15,7 @@ You are the user's sales assistant on top of their CRM. Read with the CLI, reaso
15
15
 
16
16
  **Language:** talk to the user in their language; keep commands and files in English.
17
17
 
18
- Every command is `npx -y @fleox-agent-crm/agentcrm@0.3.3 <command> --json` with `--site <alias>` (pick it with the `agentcrm-manage` skill). Command details are in the `agentcrm-admin` skill.
18
+ Every command is `npx -y @fleox-agent-crm/agentcrm@0.5.0 <command> --json` with `--site <alias>` (pick it with the `agentcrm-manage` skill). Command details are in the `agentcrm-admin` skill.
19
19
 
20
20
  ## Ground rules
21
21
 
@@ -27,10 +27,10 @@ Every command is `npx -y @fleox-agent-crm/agentcrm@0.3.3 <command> --json` with
27
27
  ## Pipeline review
28
28
 
29
29
  ```bash
30
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report pipeline --site acme --json
31
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report forecast --site acme --json
32
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report stale --site acme --json
33
- npx -y @fleox-agent-crm/agentcrm@0.3.3 records list --site acme --object deals --filter closeDate:before:today --filter stage:notIn:won,lost --json
30
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report pipeline --site acme --json
31
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report forecast --site acme --json
32
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report stale --site acme --json
33
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 records list --site acme --object deals --filter closeDate:before:today --filter stage:notIn:won,lost --json
34
34
  ```
35
35
 
36
36
  Answer with: open amount and weighted forecast (vs last review if known), deals per stage, the at-risk list (stale, close date passed, no open task, no contact), and ONE next best action per at-risk deal. Then offer to create the follow-up tasks (`tasks add … --record <dealId>`) and fix stale close dates (`records update <id> --set closeDate=…`). Playbook and next-best-action rules: references/playbooks.md.
@@ -40,9 +40,9 @@ Answer with: open amount and weighted forecast (vs last review if known), deals
40
40
  For a person, company or deal:
41
41
 
42
42
  ```bash
43
- npx -y @fleox-agent-crm/agentcrm@0.3.3 records get <id> --site acme --json
44
- npx -y @fleox-agent-crm/agentcrm@0.3.3 activities list --site acme --record <id> --related --limit 30 --json
45
- npx -y @fleox-agent-crm/agentcrm@0.3.3 tasks list --site acme --record <id> --status all --json
43
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 records get <id> --site acme --json
44
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 activities list --site acme --record <id> --related --limit 30 --json
45
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 tasks list --site acme --record <id> --status all --json
46
46
  ```
47
47
 
48
48
  Brief (one page): who they are (role, company, size, industry), relationship history (last 5 interactions, open questions, promises made), open deals (stage, amount, close date), recent public news about the company (cite links), 3 goals for the meeting, questions to ask, risks. Offer to save it as a note on the record.
@@ -54,7 +54,7 @@ Read the record and its timeline (as above), then draft the email: subject + bod
54
54
  ## Lead qualification and enrichment
55
55
 
56
56
  ```bash
57
- npx -y @fleox-agent-crm/agentcrm@0.3.3 records list --site acme --object people --filter lifecycleStage:eq:lead --sort createdAt:desc --limit 25 --json
57
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 records list --site acme --object people --filter lifecycleStage:eq:lead --sort createdAt:desc --limit 25 --json
58
58
  ```
59
59
 
60
60
  For each lead: read the record and its company; enrich from public sources (company website: size, industry, location; the person's public role); score fit (1-5) and intent from the timeline; recommend a lifecycle stage and an owner. Present a table, then apply approved changes with `records update` and log the sources with `notes add`. Details: references/enrichment.md.
@@ -62,8 +62,8 @@ For each lead: read the record and its company; enrich from public sources (comp
62
62
  ## Clean duplicates
63
63
 
64
64
  ```bash
65
- npx -y @fleox-agent-crm/agentcrm@0.3.3 records duplicates --site acme --object people --json
66
- npx -y @fleox-agent-crm/agentcrm@0.3.3 records duplicates --site acme --object companies --json
65
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 records duplicates --site acme --object people --json
66
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 records duplicates --site acme --object companies --json
67
67
  ```
68
68
 
69
69
  For each group, pick the primary (most complete, most activities), show what the merge keeps, then `records merge <primaryId> <dupId>...` (plan, then `--yes`) group by group.
@@ -71,18 +71,18 @@ For each group, pick the primary (most complete, most activities), show what the
71
71
  ## Trade show / event lead lists
72
72
 
73
73
  1. Look at the file (headers, a few rows) and map columns to people fields; put the event name in `leadSource` (add the option if missing) and `tags`.
74
- 2. Dry run: `npx -y @fleox-agent-crm/agentcrm@0.3.3 import csv leads.csv --site acme --object people --map "…" --json`. Report new vs existing contacts and errors.
74
+ 2. Dry run: `npx -y @fleox-agent-crm/agentcrm@0.5.0 import csv leads.csv --site acme --object people --map "…" --json`. Report new vs existing contacts and errors.
75
75
  3. After approval: the same with `--yes`.
76
76
  4. Offer the follow-up: a task per hot lead for its owner, or a note on each record with the booth conversation if the file has comments.
77
77
 
78
78
  ## Weekly sales report
79
79
 
80
80
  ```bash
81
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report won-lost --site acme --months 3 --json
82
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report activity --site acme --days 7 --json
83
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report pipeline --site acme --json
84
- npx -y @fleox-agent-crm/agentcrm@0.3.3 report conversion --site acme --json
85
- npx -y @fleox-agent-crm/agentcrm@0.3.3 tasks list --site acme --overdue --json
81
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report won-lost --site acme --months 3 --json
82
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report activity --site acme --days 7 --json
83
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report pipeline --site acme --json
84
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 report conversion --site acme --json
85
+ npx -y @fleox-agent-crm/agentcrm@0.5.0 tasks list --site acme --overdue --json
86
86
  ```
87
87
 
88
88
  Template and what to compute: references/weekly-report.md.
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./sdk-DtP9zqdi.js","./index-DLy5RpPl.js","./index-TcjySLVg.css","./index.esm-Dum0J07z.js","./index.esm2017-EOzKbpUS.js","./index.esm-CtEQZRb1.js"])))=>i.map(i=>d[i]);
2
- import{c as Z,w as ee,_ as te,C as A,e as ie,p as z,n as ne,r as oe,F as H,a as se}from"./index-DLy5RpPl.js";const re=Symbol("deleteField");function G(e){return(e==null?void 0:e.code)??""}function k(e){const n=G(e);return n==="permission-denied"||n==="firestore/permission-denied"}const ce=500;function ae(e,n){const i=[];for(let t=0;t<e.length;t+=n)i.push(e.slice(t,t+n));return i}const j="invites",F="extensionChunks",x=3e5,le=["admin","member","viewer"];class N extends Error{constructor(n,i,t){super(i),this.reason=n,this.email=t,this.name="FirebaseAccessError"}}function ve(e){return e.kind==="firebase"&&typeof e.accessError=="function"}function X(e){const{id:n,...i}=z(e);return i}function ue(e){return ne({...e.data,id:e.id})}function T(e){return typeof e=="string"&&le.includes(e)}function E(e){return typeof e=="string"?e.trim().toLowerCase():""}function W(e){return!!e&&!e.authUid&&!!E(e.email)}function fe(e,n,i){const t=new Map;for(const o of e){if(o.collection!=="users")continue;const r=o.op==="set"?o.doc.id:o.id,a=n(r),p=i.users.get(r),m=W(a)?E(a.email):"",w=W(p)?E(p.email):"";m&&m!==w&&t.set(m,{type:"delete",collection:j,id:m}),w&&p&&(p.disabled?t.set(w,{type:"delete",collection:j,id:w}):t.set(w,{type:"set",collection:j,id:w,data:{role:T(p.role)?p.role:"member",userId:r,email:w}}))}return[...t.values()]}const P=(e,n,i)=>`${e}__${n}__${i}`;function J(e){const n=(e==null?void 0:e.files)??{},i={};for(const[t,o]of Object.entries(n))typeof o=="string"&&(i[t]=Math.ceil(o.length/x));return i}function de(e,n){const i=e.files??{},t=Object.values(i).reduce((p,m)=>p+(typeof m=="string"?m.length:0),0),o=[],r={},a=X(e);if(t>x){for(const[p,m]of Object.entries(i)){if(typeof m!="string")continue;const w=Math.ceil(m.length/x);r[p]=w;for(let y=0;y<w;y++)o.push({type:"set",collection:F,id:P(e.id,p,y),data:{ext:e.id,file:p,index:y,data:m.slice(y*x,(y+1)*x)}})}a.files={},a.chunks=r}for(const[p,m]of Object.entries(J(n)))for(let w=r[p]??0;w<m;w++)o.push({type:"delete",collection:F,id:P(e.id,p,w)});return o.unshift({type:"set",collection:"extensions",id:e.id,data:a}),o}function pe(e,n){const i=new Map;for(const t of n){const o=String(t.data.ext??"");i.set(o,[...i.get(o)??[],t])}return e.map(t=>{const o=t.data.chunks;if(!o||typeof o!="object")return t;const r={},a=i.get(t.id)??[];for(const[w,y]of Object.entries(o)){const C=a.filter(v=>v.data.file===w).sort((v,D)=>Number(v.data.index)-Number(D.data.index));C.length===y&&(r[w]=C.map(v=>String(v.data.data??"")).join(""))}const{chunks:p,...m}=t.data;return{id:t.id,data:{...m,files:r}}})}function he(e,n){const i=[];for(const t of e)if(t.op==="set"&&t.collection==="extensions")i.push(...de(t.doc,n.extensions.get(t.doc.id)));else if(t.op==="set")i.push({type:"set",collection:t.collection,id:t.doc.id,data:X(t.doc)});else if(t.op==="delete"){if(i.push({type:"delete",collection:t.collection,id:t.id}),t.collection==="extensions")for(const[o,r]of Object.entries(J(n.extensions.get(t.id))))for(let a=0;a<r;a++)i.push({type:"delete",collection:F,id:P(t.id,o,a)})}else{if(!n[t.collection].has(t.id))continue;const o={};for(const[r,a]of Object.entries(t.fields))r==="id"||r.startsWith("id.")||(o[r]=a===void 0?re:z(a));Object.keys(o).length&&i.push({type:"update",collection:t.collection,id:t.id,data:o})}return i}const me="files",q="Firebase Storage isn't enabled for this project: enable it in the Firebase console (Build → Storage), add `storageBucket` to the web config and deploy the storage rules (docs/files.md).";function we(e){const n=()=>{if(!e.storage)throw new H(q);return e.storage},i=o=>(se(o),`${me}/${o}`),t=async o=>{try{return await o()}catch(r){const a=G(r);throw a==="storage/unknown"||a==="storage/bucket-not-found"||a==="storage/no-default-bucket"?new H(q):r}};return{kind:"firebase",put:(o,r,a)=>t(()=>n().put(i(o),r,a==null?void 0:a.mime)),async putMany(o){for(const r of o)await t(()=>{var a;return n().put(i(r.id),r.bytes,(a=r.meta)==null?void 0:a.mime)})},get:o=>t(()=>n().get(i(o))),delete:o=>t(()=>n().delete(i(o)))}}function ge(e){const n=e.api,i=e.requireVerifiedEmail!==!1,t=e.now??Date.now;let o=null,r=null,a=null,p=new Map,m=!1;const w=n.auth.onChange(s=>{(!s||s.uid!==(r==null?void 0:r.uid))&&(o=null,r=null)});function y(s,c){const f=ie();for(const d of A){const h=d==="extensions"?pe(s.get(d)??[],c):s.get(d)??[];for(const l of h)f[d].set(l.id,ue(l))}p=new Map(f.users);for(const d of[...f.users.values()])typeof d.replaces=="string"&&d.replaces!==d.id&&f.users.delete(d.replaces);return f}async function C(s){try{return await n.listCollection(s)}catch(c){if(k(c))return[];throw c}}async function v(s){const c=E(s.email);let f=null;try{f=await n.getDoc("users",s.uid)}catch(u){if(!k(u))throw u}if(f)return T(f.role)?f.role:"viewer";if(i&&!s.emailVerified)throw new N("unverified","Verify your email address to continue.",c);const d={email:c,name:s.displayName||c.split("@")[0]||"User",authUid:s.uid,createdAt:t(),updatedAt:t(),...s.photoURL?{avatarUrl:s.photoURL}:{}},h=(u,b={})=>n.commit([{type:"set",collection:"users",id:s.uid,data:{...d,...b,role:u}}]);try{return await h("admin"),"admin"}catch(u){if(!k(u))throw u}let l=null;try{l=c?await n.getDoc(j,c):null}catch(u){if(!k(u))throw u}const g=l&&T(l.role)?l.role:"member";try{return await h(g,l&&typeof l.userId=="string"?{replaces:l.userId}:{}),g}catch(u){if(!k(u))throw u}throw new N("notInvited","This account has not been invited to this CRM. Ask an admin to add your email in Settings → Users.",c)}async function D(){const s=await n.auth.currentUser();if(!s)return a=null,null;try{const c=await v(s);return a=null,{uid:s.uid,email:E(s.email),displayName:s.displayName||E(s.email),role:c}}catch(c){return a=c instanceof N?c:new N("error",c.message,E(s.email)),null}}function B(){return o||(o=D().then(s=>(r=s,s||(o=null),s))),o}async function Q(s,c,f){const d=he(s,c);!r&&s.some(h=>h.collection==="users")&&await B(),(r==null?void 0:r.role)==="admin"&&d.push(...fe(s,h=>c.users.get(h)??p.get(h),f));for(const h of ae(d,ce))await n.commit(h);for(const h of s){if(h.collection!=="users")continue;const l=h.op==="set"?h.doc.id:h.id,g=f.users.get(l);g?p.set(l,g):p.delete(l)}}const S=Z({kind:"firebase",async load(){const s=new Map;let c=[];await Promise.all([...A.map(async d=>s.set(d,await C(d))),C(F).then(d=>c=d)]);const f=y(s,c);return V(),f},persist:(s,c,f)=>Q(s,c,f),watch(s){const c=new Map;let f=null;const d=()=>{c.size<A.length||f===null||(s(y(c,f)),V())},h=A.map(l=>n.watchCollection(l,g=>{c.set(l,g),d()},g=>{k(g)?c.set(l,[]):console.warn(`[firebase] live updates of ${l} stopped:`,g)}));return h.push(n.watchCollection(F,l=>{f=l,d()},l=>{k(l)?f=[]:console.warn("[firebase] live updates of extension chunks stopped:",l)})),()=>h.forEach(l=>l())},identity:B,close(){w()}});function V(){if((r==null?void 0:r.role)!=="admin"||m)return;const s=[...p.values()].filter(c=>typeof c.replaces=="string");s.length&&(m=!0,setTimeout(()=>{Y(s).finally(()=>m=!1)},0))}async function Y(s){var l;const c=[],f=[],d=S.list("objects"),h=new Map(d.map(g=>[g.id,(g.fields??[]).filter(u=>u.type==="user").map(u=>u.id)]));for(const g of s){const u=g.replaces,b=g.id,I=p.get(u);for(const O of S.list("records")){const _={};O.ownerId===u&&(_.ownerId=b),O.createdBy===u&&(_.createdBy=b);for(const M of h.get(O.object)??[]){const L=(l=O.fields)==null?void 0:l[M];L===u?_[`fields.${M}`]=b:Array.isArray(L)&&L.includes(u)&&(_[`fields.${M}`]=L.map(K=>K===u?b:K))}Object.keys(_).length&&c.push({op:"patch",collection:"records",id:O.id,fields:_})}for(const O of S.list("activities"))O.assigneeId===u&&c.push({op:"patch",collection:"activities",id:O.id,fields:{assigneeId:b}});const R=S.get("settings","general");(R==null?void 0:R.ownerUserId)===u&&c.push({op:"patch",collection:"settings",id:"general",fields:{ownerUserId:b}}),I&&(c.push({op:"delete",collection:"users",id:u}),E(I.email)&&f.push({type:"delete",collection:j,id:E(I.email)})),c.push({op:"patch",collection:"users",id:b,fields:{replaces:void 0,...I&&I.role!==g.role&&T(I.role)?{role:I.role}:{}}})}try{await S.write(c,{message:"Link invited users"}),f.length&&await n.commit(f)}catch(g){console.warn("[firebase] could not link invited users:",g)}}return ee(S,we(n)),Object.assign(S,{api:n,accessError:()=>a,resetSession(){o=null,r=null,a=null}})}const $=new Map;function ye(e){const n=e.firebase.projectId??"default";let i=$.get(n);return i||(i=te(()=>import("./sdk-DtP9zqdi.js"),__vite__mapDeps([0,1,2,3,4,5]),import.meta.url).then(t=>t.createSdkFirebaseApi(e.firebase)),$.set(n,i),i.catch(()=>$.delete(n))),i}let U=null;oe("firebase",{async signOut(){await(U==null?void 0:U.auth.signOut())}});function be(e){const n=typeof(e==null?void 0:e.email)=="string"?e.email.trim():"",i=typeof(e==null?void 0:e.password)=="string"?e.password:"";return n&&i?{email:n,password:i}:null}async function Ee(e,n){const i=be(n);if(!i)return null;const t=await e.auth.currentUser();return t!=null&&t.email&&t.email.toLowerCase()===i.email.toLowerCase()?t:(t&&await e.auth.signOut(),e.auth.signInWithPassword(i.email,i.password))}async function Se(e,n={}){var o;const i=e;if(!((o=i.firebase)!=null&&o.apiKey)||!i.firebase.projectId)throw new Error("The Firebase web config (apiKey, projectId) is missing.");const t=await ye(i);return U=t,await Ee(t,n.secrets),ge({api:t})}export{re as DELETE_FIELD,F as EXTENSION_CHUNKS_COLLECTION,x as EXTENSION_CHUNK_CHARS,ce as FIRESTORE_BATCH_LIMIT,N as FirebaseAccessError,j as INVITES_COLLECTION,me as STORAGE_FILES_DIR,q as STORAGE_NOT_ENABLED,pe as assembleExtensionDocs,ae as chunk,Se as createFirebaseStore,ge as createFirebaseStoreWith,E as emailKey,G as errorCode,ye as firebaseApiFor,we as firebaseFileStore,fe as inviteOps,ve as isFirebaseStore,k as isPermissionDenied,he as mutationOps,Ee as signInWithSecrets};
@@ -1,27 +0,0 @@
1
- import { createRequire as __acrmRequire } from "node:module";
2
- import { fileURLToPath as __acrmPath } from "node:url";
3
- import { dirname as __acrmDirname } from "node:path";
4
- const require2 = __acrmRequire(import.meta.url);
5
- const __filename = __acrmPath(import.meta.url);
6
- const __dirname = __acrmDirname(__filename);
7
- const DELETE_FIELD = Symbol("deleteField");
8
- function errorCode(err) {
9
- return err?.code ?? "";
10
- }
11
- function isPermissionDenied(err) {
12
- const code = errorCode(err);
13
- return code === "permission-denied" || code === "firestore/permission-denied";
14
- }
15
- const FIRESTORE_BATCH_LIMIT = 500;
16
- function chunk(items, size) {
17
- const out = [];
18
- for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
19
- return out;
20
- }
21
- export {
22
- DELETE_FIELD as D,
23
- FIRESTORE_BATCH_LIMIT as F,
24
- chunk as c,
25
- errorCode as e,
26
- isPermissionDenied as i
27
- };