@synity/bitrix-skills 1.3.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/CHANGELOG.md +169 -0
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/bin/bitrix-skills.js +3 -0
- package/dist/cli.js +1510 -0
- package/dist/features/bx-task/install.js +111 -0
- package/dist/features/task-sync/index.js +1053 -0
- package/package.json +69 -0
- package/src/features/bx/assets/SKILL.md +34 -0
- package/src/features/bx/feature.json +8 -0
- package/src/features/bx-calendar/assets/SKILL.md +61 -0
- package/src/features/bx-calendar/assets/availability.md +65 -0
- package/src/features/bx-calendar/assets/meeting.md +87 -0
- package/src/features/bx-calendar/assets/reminder.md +71 -0
- package/src/features/bx-calendar/assets/sync.md +70 -0
- package/src/features/bx-calendar/feature.json +10 -0
- package/src/features/bx-crm/assets/SKILL.md +59 -0
- package/src/features/bx-crm/assets/commerce.md +96 -0
- package/src/features/bx-crm/assets/onboard.md +127 -0
- package/src/features/bx-crm/assets/report.md +98 -0
- package/src/features/bx-crm/assets/research.md +71 -0
- package/src/features/bx-crm/feature.json +10 -0
- package/src/features/bx-task/assets/SKILL.md +148 -0
- package/src/features/bx-task/assets/lib/bx-api.sh +39 -0
- package/src/features/bx-task/assets/lib/bx-checklist.sh +127 -0
- package/src/features/bx-task/assets/lib/bx-resolve-task.sh +41 -0
- package/src/features/bx-task/assets/lib/bx-state.sh +131 -0
- package/src/features/bx-task/assets/lib/bx-tasks.sh +109 -0
- package/src/features/bx-task/assets/references/bootstrap.md +184 -0
- package/src/features/bx-task/assets/references/feature.md +97 -0
- package/src/features/bx-task/assets/references/init-templates/cli-tool.md +47 -0
- package/src/features/bx-task/assets/references/init-templates/generic.md +31 -0
- package/src/features/bx-task/assets/references/init-templates/library.md +45 -0
- package/src/features/bx-task/assets/references/init-templates/monorepo.md +38 -0
- package/src/features/bx-task/assets/references/init-templates/npm-package.md +40 -0
- package/src/features/bx-task/assets/references/init-templates/web-app.md +46 -0
- package/src/features/bx-task/assets/references/init.md +107 -0
- package/src/features/bx-task/assets/references/roadmap.md +93 -0
- package/src/features/bx-task/assets/references/summary.md +269 -0
- package/src/features/bx-task/assets/references/sync.md +104 -0
- package/src/features/bx-task/assets/references/time-log.md +214 -0
- package/src/features/bx-task/feature.json +10 -0
- package/src/features/bx-task/install.ts +117 -0
- package/src/features/task-sync/assets/docs/bitrix-task-reference.md +318 -0
- package/src/features/task-sync/assets/docs/bitrix-task-sync.md +254 -0
- package/src/features/task-sync/assets/githooks/commit-msg +44 -0
- package/src/features/task-sync/assets/githooks/install.sh +15 -0
- package/src/features/task-sync/assets/manifest.json +108 -0
- package/src/features/task-sync/assets/rules/00-bitrix-task-sync.md +161 -0
- package/src/features/task-sync/assets/scripts/bitrix-attach-files.sh +55 -0
- package/src/features/task-sync/assets/scripts/bitrix-lib.sh +540 -0
- package/src/features/task-sync/assets/scripts/bitrix-render-digest.sh +116 -0
- package/src/features/task-sync/assets/scripts/bitrix-session-check.sh +51 -0
- package/src/features/task-sync/assets/scripts/bitrix-session-sync.sh +89 -0
- package/src/features/task-sync/assets/scripts/bitrix-skill-end.sh +165 -0
- package/src/features/task-sync/assets/scripts/bitrix-skill-start.sh +58 -0
- package/src/features/task-sync/assets/scripts/lib/bb-formatter.sh +110 -0
- package/src/features/task-sync/assets/scripts/lib/bitrix-lib.sh +540 -0
- package/src/features/task-sync/assets/scripts/lib/time-helpers.sh +57 -0
- package/src/features/task-sync/assets/workflows/bitrix-sync.yml +85 -0
- package/src/features/task-sync/commands/install.ts +296 -0
- package/src/features/task-sync/commands/uninstall.ts +189 -0
- package/src/features/task-sync/commands/update.ts +11 -0
- package/src/features/task-sync/commands/verify.ts +141 -0
- package/src/features/task-sync/feature.json +12 -0
- package/src/features/task-sync/index.ts +121 -0
- package/src/features/task-sync/lib/dest-map.ts +96 -0
- package/src/features/task-sync/lib/drift-check.ts +47 -0
- package/src/features/task-sync/lib/file-ops.ts +36 -0
- package/src/features/task-sync/lib/manifest.ts +66 -0
- package/src/features/task-sync/lib/project-root.ts +38 -0
- package/src/features/task-sync/lib/settings-merge.ts +112 -0
- package/src/features/task-sync/lib/skill-refs.ts +106 -0
- package/src/features/task-sync/lib/task-id-finder.ts +31 -0
- package/src/features/task-sync/lib/token-extractor.ts +52 -0
- package/src/features/task-sync/lib/version.ts +36 -0
- package/src/features/task-sync/types.ts +40 -0
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@synity/bitrix-skills",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Multi-feature Bitrix24 tooling CLI for Synity projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"bitrix-skills": "bin/bitrix-skills.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"bin",
|
|
12
|
+
"src/features",
|
|
13
|
+
"README.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/synity-tech/bitrix-tools.git"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/synity-tech/bitrix-tools",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/synity-tech/bitrix-tools/issues"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"prebuild": "node scripts/prebuild-bash-sync.mjs && node scripts/sync-assets.mjs",
|
|
29
|
+
"build": "tsup --config tsup.config.ts",
|
|
30
|
+
"dev": "tsup --config tsup.config.ts --watch",
|
|
31
|
+
"prepublishOnly": "pnpm build",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"lint": "eslint src --ext .ts",
|
|
35
|
+
"release": "pnpm build && changeset publish",
|
|
36
|
+
"version": "changeset version",
|
|
37
|
+
"changeset": "changeset"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"bitrix24",
|
|
44
|
+
"bitrix",
|
|
45
|
+
"task-sync",
|
|
46
|
+
"claude-code",
|
|
47
|
+
"ai-tools",
|
|
48
|
+
"hooks",
|
|
49
|
+
"synity"
|
|
50
|
+
],
|
|
51
|
+
"author": "Synity Vietnam JSC <tech@synity.vn>",
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@inquirer/checkbox": "^5.1.5",
|
|
55
|
+
"@inquirer/confirm": "^6.0.13",
|
|
56
|
+
"chalk": "^5.6.2",
|
|
57
|
+
"clipanion": "4.0.0-rc.4",
|
|
58
|
+
"deepmerge": "^4.3.1",
|
|
59
|
+
"execa": "^9.0.0",
|
|
60
|
+
"kleur": "^4.1.5"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@changesets/cli": "^2.31.0",
|
|
64
|
+
"@types/node": "^20.0.0",
|
|
65
|
+
"tsup": "^8.0.0",
|
|
66
|
+
"typescript": "^5.4.0",
|
|
67
|
+
"vitest": "^2.1.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bx
|
|
3
|
+
description: "Bitrix24 hub — type /bx to discover all Bitrix24 skills. Routes to bx:crm (contacts/deals), bx:task (project tasks), bx:calendar (events/meetings)."
|
|
4
|
+
argument-hint: "[crm|task|calendar]"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /bx — Bitrix24 Skill Hub
|
|
9
|
+
|
|
10
|
+
Detect intent → invoke the right subskill directly.
|
|
11
|
+
|
|
12
|
+
| User intent | Invoke |
|
|
13
|
+
|-------------|--------|
|
|
14
|
+
| contact, deal, company, lead, phân tích KH, báo giá, invoice, pipeline report | `/bx:crm` |
|
|
15
|
+
| task, time-log, KB summary, sync session to Bitrix, init TASK_ID | `/bx:task` |
|
|
16
|
+
| meeting, lịch, calendar, nhắc nhở, schedule, kiểm tra lịch trống | `/bx:calendar` |
|
|
17
|
+
|
|
18
|
+
> **Tip:** If you already know the domain, invoke the subskill directly — faster than routing through `/bx`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## If intent is ambiguous
|
|
23
|
+
|
|
24
|
+
Ask: **"CRM, task management, or calendar?"** then invoke the correct subskill.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Subskill Quick Reference
|
|
29
|
+
|
|
30
|
+
| Skill | Version | Coverage |
|
|
31
|
+
|-------|---------|---------|
|
|
32
|
+
| `bx:crm` | v2.0.0 | contact/company/deal/lead, analysis, reports, commerce |
|
|
33
|
+
| `bx:task` | v1.1.0 | task CRUD, time-log, KB summary, session sync |
|
|
34
|
+
| `bx:calendar` | v1.0.0 | events, meetings, reminders, availability, CRM sync |
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bx:calendar
|
|
3
|
+
description: "Synity Bitrix24 Calendar via REST API. Use for: creating meetings, scheduling events, follow-up reminders, checking team availability, syncing CRM activities to calendar. NOT for CRM records (use bx:crm) or project tasks (use bx:task)."
|
|
4
|
+
argument-hint: "<subcommand> [args...]"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /bx:calendar — Bitrix24 Calendar Operations (Synity)
|
|
9
|
+
|
|
10
|
+
**Tool**: Bitrix24 REST API via `BITRIX_WEBHOOK_URL` — no MCP Synity helpers for calendar.
|
|
11
|
+
|
|
12
|
+
> ⛔ `bx:crm` = CRM entities (contact/deal). NOT for calendar events.
|
|
13
|
+
> ⛔ `bx:task` = project task management. NOT for calendar events.
|
|
14
|
+
> ✅ All calendar events, meetings, reminders, scheduling → this skill.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Pre-flight (mandatory)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Required env var
|
|
22
|
+
echo $BITRIX_WEBHOOK_URL # must be set: https://<portal>.bitrix24.com/rest/<user>/<token>/
|
|
23
|
+
|
|
24
|
+
# Required tools
|
|
25
|
+
which jq curl
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Detect Intent → Load File
|
|
31
|
+
|
|
32
|
+
| User intent | Load file |
|
|
33
|
+
|-------------|-----------|
|
|
34
|
+
| Create meeting, schedule event, link to CRM contact/deal | `meeting.md` |
|
|
35
|
+
| Set reminder, follow-up after meeting | `reminder.md` |
|
|
36
|
+
| Check availability, find free time slot | `availability.md` |
|
|
37
|
+
| Sync CRM activity to calendar event | `sync.md` |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Mandatory Workflow
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
1. Detect intent → load the correct subfile above
|
|
45
|
+
2. Follow SOP in that file (timezone, CRM binding)
|
|
46
|
+
3. Execute via REST API (curl + jq)
|
|
47
|
+
4. Verify result
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## REST API Basics
|
|
53
|
+
|
|
54
|
+
**Input parameters**: camelCase (`name`, `ownerId`, `from`, `to`)
|
|
55
|
+
**Response fields**: UPPER_SNAKE_CASE (`TZ_FROM`, `TZ_TO`, `ID`)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Generic REST call pattern
|
|
59
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.add" \
|
|
60
|
+
-d "$(jq -n '{fields: {name: "...", ...}}')" | jq .
|
|
61
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# bx:calendar — Availability (Find Free Slots)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Query Events for a User
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Get all events for user 1 in a date range
|
|
9
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.getlist" \
|
|
10
|
+
-d "$(jq -n '{
|
|
11
|
+
type: "user",
|
|
12
|
+
ownerId: 1,
|
|
13
|
+
from: "2026-05-16",
|
|
14
|
+
to: "2026-05-16"
|
|
15
|
+
}')" | jq '[.result[] | {id:.ID, name:.NAME, from:.DATE_FROM, to:.DATE_TO}]'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Parameters:**
|
|
19
|
+
| Parameter | Value |
|
|
20
|
+
|-----------|-------|
|
|
21
|
+
| `type` | `"user"` for personal calendar |
|
|
22
|
+
| `ownerId` | Bitrix24 user ID |
|
|
23
|
+
| `from` | Date string `"YYYY-MM-DD"` |
|
|
24
|
+
| `to` | Date string `"YYYY-MM-DD"` |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Free Slot Algorithm
|
|
29
|
+
|
|
30
|
+
1. Fetch busy events for each attendee in the target date range
|
|
31
|
+
2. Normalize all event times to VN timezone (`Asia/Ho_Chi_Minh`, UTC+7)
|
|
32
|
+
3. Merge busy intervals per attendee → find gaps ≥ `meetingDuration`
|
|
33
|
+
4. Intersect free gaps across all attendees
|
|
34
|
+
5. Filter to working hours: **08:00–17:30 VN** (configurable)
|
|
35
|
+
|
|
36
|
+
**Output format:**
|
|
37
|
+
```
|
|
38
|
+
Free slots for [date]:
|
|
39
|
+
- 08:00–10:00 (2h)
|
|
40
|
+
- 13:00–15:30 (2.5h)
|
|
41
|
+
- 16:00–17:30 (1.5h)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Multi-User Availability Check
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Check availability for users 1, 2, 3
|
|
50
|
+
for USER_ID in 1 2 3; do
|
|
51
|
+
echo "=== User $USER_ID ==="
|
|
52
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.getlist" \
|
|
53
|
+
-d "$(jq -n --argjson uid $USER_ID '{type:"user", ownerId:$uid, from:"2026-05-16", to:"2026-05-16"}')" \
|
|
54
|
+
| jq '[.result[] | {from:.DATE_FROM, to:.DATE_TO, name:.NAME}]'
|
|
55
|
+
done
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Notes
|
|
61
|
+
|
|
62
|
+
- Working hours assumption: 08:00–17:30 VN — adjust if user has different hours
|
|
63
|
+
- `calendar.event.getlist` returns events where the querying user has read access
|
|
64
|
+
- Response `DATE_FROM` / `DATE_TO` are in UPPER_SNAKE_CASE
|
|
65
|
+
- All-day events: `DATE_FROM` has no time component — treat as blocking 00:00–23:59
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# bx:calendar — Meeting (Create Event + CRM Binding)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Required Fields for calendar.event.add
|
|
6
|
+
|
|
7
|
+
| Parameter | Type | Notes |
|
|
8
|
+
|-----------|------|-------|
|
|
9
|
+
| `name` | string | Event title |
|
|
10
|
+
| `type` | string | `"user"` (personal) / `"group"` (team) / `"company_calendar"` |
|
|
11
|
+
| `ownerId` | number | User ID (for `type=user`) or group ID |
|
|
12
|
+
| `from` | string | ISO 8601: `"2026-05-15T10:00:00+07:00"` |
|
|
13
|
+
| `to` | string | ISO 8601: `"2026-05-15T11:00:00+07:00"` |
|
|
14
|
+
| `section` | number | Section ID from `calendar.section.getlist` |
|
|
15
|
+
| `timezone_from` | string | **Always `"Asia/Ho_Chi_Minh"` for VN meetings** |
|
|
16
|
+
| `timezone_to` | string | **Always `"Asia/Ho_Chi_Minh"` for VN meetings** |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Timezone SOP (CRITICAL)
|
|
21
|
+
|
|
22
|
+
**Always set `timezone_from` and `timezone_to` = `"Asia/Ho_Chi_Minh"`** for VN meetings.
|
|
23
|
+
|
|
24
|
+
Omitting timezone → server stores UTC → all VN participants see wrong time.
|
|
25
|
+
|
|
26
|
+
Use ISO 8601 with offset in datetime strings:
|
|
27
|
+
```
|
|
28
|
+
"2026-05-15T10:00:00+07:00" ✅ correct
|
|
29
|
+
"2026-05-15T03:00:00Z" ❌ confusing — use +07:00 explicitly
|
|
30
|
+
"2026-05-15 10:00:00" ❌ no timezone info
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## CRM Binding
|
|
36
|
+
|
|
37
|
+
Link the event to a CRM entity via `UF_CRM_CAL_EVENT`:
|
|
38
|
+
|
|
39
|
+
| Entity | Prefix format |
|
|
40
|
+
|--------|--------------|
|
|
41
|
+
| Deal | `D_<dealId>` → e.g. `"D_42"` |
|
|
42
|
+
| Contact | `CO_<contactId>` → e.g. `"CO_15"` |
|
|
43
|
+
| Company | `C_<companyId>` → e.g. `"C_7"` |
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Example: meeting linked to deal 42 + contact 15
|
|
47
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.add" \
|
|
48
|
+
-d "$(jq -n '{
|
|
49
|
+
name: "Demo call with Nguyen Van A",
|
|
50
|
+
type: "user",
|
|
51
|
+
ownerId: 1,
|
|
52
|
+
from: "2026-05-16T10:00:00+07:00",
|
|
53
|
+
to: "2026-05-16T11:00:00+07:00",
|
|
54
|
+
section: 3,
|
|
55
|
+
timezone_from: "Asia/Ho_Chi_Minh",
|
|
56
|
+
timezone_to: "Asia/Ho_Chi_Minh",
|
|
57
|
+
UF_CRM_CAL_EVENT: ["D_42", "CO_15"]
|
|
58
|
+
}')" | jq '.result'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Get Section ID
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.section.getlist" \
|
|
67
|
+
-d '{"type":"user","ownerId":1}' | jq '[.result[] | {id:.ID, name:.NAME}]'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Verify Checklist
|
|
73
|
+
|
|
74
|
+
- [ ] Event `ID` returned (not null)
|
|
75
|
+
- [ ] Response `TZ_FROM` = `"Asia/Ho_Chi_Minh"`
|
|
76
|
+
- [ ] `UF_CRM_CAL_EVENT` contains expected entity IDs
|
|
77
|
+
- [ ] `from` / `to` datetimes correct
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Common Mistakes
|
|
82
|
+
|
|
83
|
+
| Mistake | Result | Fix |
|
|
84
|
+
|---------|--------|-----|
|
|
85
|
+
| Omit `timezone_from`/`timezone_to` | Server timezone (UTC) stored | Always set both |
|
|
86
|
+
| Wrong CRM prefix (`DEAL_42` instead of `D_42`) | Binding silently ignored | Use exact prefixes above |
|
|
87
|
+
| Missing `section` field | API error | Fetch section ID first |
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# bx:calendar — Reminder (Follow-up + Pre-meeting)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Two Reminder Use Cases
|
|
6
|
+
|
|
7
|
+
### Use Case 1 — Pre-meeting notification
|
|
8
|
+
|
|
9
|
+
Add `remind` array to event creation:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.add" \
|
|
13
|
+
-d "$(jq -n '{
|
|
14
|
+
name: "Demo call",
|
|
15
|
+
type: "user",
|
|
16
|
+
ownerId: 1,
|
|
17
|
+
from: "2026-05-16T10:00:00+07:00",
|
|
18
|
+
to: "2026-05-16T11:00:00+07:00",
|
|
19
|
+
section: 3,
|
|
20
|
+
timezone_from: "Asia/Ho_Chi_Minh",
|
|
21
|
+
timezone_to: "Asia/Ho_Chi_Minh",
|
|
22
|
+
remind: [{type: "min", count: 15}]
|
|
23
|
+
}')" | jq '.result'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**`remind` type values**: `"min"` | `"hour"` | `"day"`
|
|
27
|
+
|
|
28
|
+
**Standard offsets:**
|
|
29
|
+
- Pre-meeting: `{type: "min", count: 15}` (15 min before)
|
|
30
|
+
- Long event: `{type: "hour", count: 1}` (1 hour before)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### Use Case 2 — Post-meeting follow-up
|
|
35
|
+
|
|
36
|
+
Create a **new event** scheduled `+1 business day` after meeting end.
|
|
37
|
+
|
|
38
|
+
**Business day calculation rule:**
|
|
39
|
+
- If meeting ends Mon–Thu → follow-up = next day at 09:00
|
|
40
|
+
- If meeting ends Fri → follow-up = Monday at 09:00
|
|
41
|
+
- If meeting ends Sat/Sun → follow-up = Monday at 09:00
|
|
42
|
+
- VN public holidays: out of scope (skip manually if needed)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Follow-up event after meeting with deal 42
|
|
46
|
+
FOLLOW_UP_DATE="2026-05-17T09:00:00+07:00" # calculated +1 biz day
|
|
47
|
+
FOLLOW_UP_END="2026-05-17T09:30:00+07:00"
|
|
48
|
+
|
|
49
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.add" \
|
|
50
|
+
-d "$(jq -n --arg d "$FOLLOW_UP_DATE" --arg e "$FOLLOW_UP_END" '{
|
|
51
|
+
name: "Follow-up: Demo call with Nguyen Van A",
|
|
52
|
+
type: "user",
|
|
53
|
+
ownerId: 1,
|
|
54
|
+
from: $d,
|
|
55
|
+
to: $e,
|
|
56
|
+
section: 3,
|
|
57
|
+
timezone_from: "Asia/Ho_Chi_Minh",
|
|
58
|
+
timezone_to: "Asia/Ho_Chi_Minh",
|
|
59
|
+
UF_CRM_CAL_EVENT: ["D_42"],
|
|
60
|
+
remind: [{type: "min", count: 30}]
|
|
61
|
+
}')" | jq '.result'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Verify Checklist
|
|
67
|
+
|
|
68
|
+
- [ ] Event `ID` returned
|
|
69
|
+
- [ ] For pre-meeting: `remind` array present in event details
|
|
70
|
+
- [ ] For follow-up: datetime is a business day at 09:00 VN time
|
|
71
|
+
- [ ] CRM deal/contact linked via `UF_CRM_CAL_EVENT`
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# bx:calendar — Sync (CRM Activity → Calendar Event)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Direction
|
|
6
|
+
|
|
7
|
+
**One-way only: CRM Activity → Calendar Event.**
|
|
8
|
+
|
|
9
|
+
No native Bitrix24 webhook for 2-way sync. After creation:
|
|
10
|
+
- Editing the calendar event does NOT update the CRM activity
|
|
11
|
+
- Editing the CRM activity does NOT update the calendar event
|
|
12
|
+
- Manual update required if either changes after sync
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Field Mapping
|
|
17
|
+
|
|
18
|
+
| CRM Activity field | Calendar event parameter | Notes |
|
|
19
|
+
|-------------------|-------------------------|-------|
|
|
20
|
+
| `SUBJECT` | `name` | Event title |
|
|
21
|
+
| `START_TIME` | `from` | ISO 8601 + `+07:00` offset |
|
|
22
|
+
| `END_TIME` | `to` | ISO 8601 + `+07:00` offset |
|
|
23
|
+
| `DESCRIPTION` | `description` | Optional |
|
|
24
|
+
| `OWNER_TYPE_ID` + `OWNER_ID` | `UF_CRM_CAL_EVENT` | e.g. deal → `["D_42"]` |
|
|
25
|
+
| `RESPONSIBLE_ID` | `ownerId` | Bitrix24 user ID |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Sync Steps
|
|
30
|
+
|
|
31
|
+
**Step 1 — Read CRM activity**
|
|
32
|
+
```bash
|
|
33
|
+
curl -s "${BITRIX_WEBHOOK_URL}crm.activity.get" \
|
|
34
|
+
-d '{"id": 789}' | jq '.result | {subject:.SUBJECT, start:.START_TIME, end:.END_TIME, owner_type:.OWNER_TYPE_ID, owner_id:.OWNER_ID}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Step 2 — Map owner to CRM entity prefix**
|
|
38
|
+
|
|
39
|
+
| `OWNER_TYPE_ID` | Prefix |
|
|
40
|
+
|----------------|--------|
|
|
41
|
+
| 2 | `CO_` (contact) |
|
|
42
|
+
| 3 | `C_` (company) |
|
|
43
|
+
| 4 | `D_` (deal) |
|
|
44
|
+
|
|
45
|
+
**Step 3 — Create calendar event**
|
|
46
|
+
```bash
|
|
47
|
+
curl -s "${BITRIX_WEBHOOK_URL}calendar.event.add" \
|
|
48
|
+
-d "$(jq -n '{
|
|
49
|
+
name: "Meeting: <SUBJECT>",
|
|
50
|
+
type: "user",
|
|
51
|
+
ownerId: <RESPONSIBLE_ID>,
|
|
52
|
+
from: "<START_TIME_ISO+07:00>",
|
|
53
|
+
to: "<END_TIME_ISO+07:00>",
|
|
54
|
+
section: 3,
|
|
55
|
+
timezone_from: "Asia/Ho_Chi_Minh",
|
|
56
|
+
timezone_to: "Asia/Ho_Chi_Minh",
|
|
57
|
+
UF_CRM_CAL_EVENT: ["D_<OWNER_ID>"]
|
|
58
|
+
}')" | jq '.result'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Step 4 — Verify**
|
|
62
|
+
- [ ] Calendar event `ID` returned
|
|
63
|
+
- [ ] `UF_CRM_CAL_EVENT` contains correct CRM entity
|
|
64
|
+
- [ ] `TZ_FROM` = `"Asia/Ho_Chi_Minh"` in response
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Limitation Note
|
|
69
|
+
|
|
70
|
+
> **After sync:** if you edit the calendar event or the CRM activity, the other side will NOT be updated automatically. This is a Bitrix24 platform limitation — no native 2-way sync via REST API. To update both, edit both manually.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bx-calendar",
|
|
3
|
+
"displayName": "Bitrix Calendar Skill",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"target": "global",
|
|
6
|
+
"description": "Claude Code skill for Bitrix24 Calendar: meetings, reminders, team availability, CRM activity sync",
|
|
7
|
+
"requires": {
|
|
8
|
+
"env": ["BITRIX_WEBHOOK_URL"]
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bx:crm
|
|
3
|
+
description: "Synity Bitrix24 CRM via MCP Synity. Use for: contacts, companies, deals, leads, estimates, invoices, customer analysis, pipeline reports. NOT for project tasks (use bx:task) or calendar events (use bx:calendar)."
|
|
4
|
+
argument-hint: "<operation> [args]"
|
|
5
|
+
version: "2.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /bx:crm — Bitrix24 CRM via MCP Synity
|
|
9
|
+
|
|
10
|
+
**Tool**: MCP Synity at `b24-mcp.synity.so` — entry point is `codemode.search()` → `execute`.
|
|
11
|
+
|
|
12
|
+
> ⛔ `bx:task` = project task management. NOT for CRM entities.
|
|
13
|
+
> ⛔ `bx:calendar` = calendar events + meetings. NOT for CRM entities.
|
|
14
|
+
> ✅ All CRM (contact/company/deal/lead/estimate/invoice) → this skill.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Detect Workflow → Load File
|
|
19
|
+
|
|
20
|
+
| User intent | Load file | Key helpers |
|
|
21
|
+
|-------------|-----------|-------------|
|
|
22
|
+
| create/update contact, company, deal, lead | `onboard.md` | upsertContact, upsertCompanyByTaxCode, createDealWithParties |
|
|
23
|
+
| analyze customer, signals, before meeting | `research.md` | customer360, contactSignals, dealSignals, customerJourney |
|
|
24
|
+
| pipeline report, forecast, AR, overdue | `report.md` | dealForecast, stuckInStage, arReport |
|
|
25
|
+
| estimate, báo giá, invoice, approve | `commerce.md` | createEstimate, approveEstimate, createSmartInvoice |
|
|
26
|
+
|
|
27
|
+
If intent spans multiple workflows → load `onboard.md` first, then load others as needed.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Mandatory Workflow
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
1. Detect intent → load the correct subfile above
|
|
35
|
+
2. Follow SOP rules / output protocol in that file
|
|
36
|
+
3. codemode.search() to confirm helper schema
|
|
37
|
+
4. Execute via the correct helper
|
|
38
|
+
5. Verify result against checklist in the subfile
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Skipping steps 1 or 5 caused production bugs. Both are required.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Discovery Reference
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
// Primary — always use first
|
|
49
|
+
codemode.search({ keywords: ["..."], entities: ["deal","contact","company"], intent: "write" })
|
|
50
|
+
|
|
51
|
+
// Only if search() returns empty
|
|
52
|
+
codemode.catalog() // ~40 unranked helpers
|
|
53
|
+
|
|
54
|
+
// For stage IDs / CRM type IDs
|
|
55
|
+
codemode.entityIds()
|
|
56
|
+
|
|
57
|
+
// Raw REST when no helper exists
|
|
58
|
+
codemode.request({ method: "POST", path: "/crm.xxx", body: { ... } })
|
|
59
|
+
```
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# bx:crm — Commerce (Quote-to-Cash Flow)
|
|
2
|
+
|
|
3
|
+
Covers: estimate → approve → smart invoice.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Mandatory Flow Order
|
|
8
|
+
|
|
9
|
+
**Do NOT skip or reorder these steps.**
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
1. createEstimate
|
|
13
|
+
2. setEstimateProducts
|
|
14
|
+
3. [Customer confirmation]
|
|
15
|
+
4. approveEstimate
|
|
16
|
+
5. closeEstimatesForDeal
|
|
17
|
+
6. createSmartInvoice
|
|
18
|
+
7. setInvoiceProducts OR copyDealProductsToInvoice
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Step Details
|
|
24
|
+
|
|
25
|
+
**Step 1 — Create estimate**
|
|
26
|
+
```js
|
|
27
|
+
createEstimate({ dealId, title, currency })
|
|
28
|
+
// → returns estimateId
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Step 2 — Set products**
|
|
32
|
+
```js
|
|
33
|
+
// Option A: known products from catalog
|
|
34
|
+
findProducts({ query: "product name" }) // → [{id, name, price}]
|
|
35
|
+
setEstimateProducts({ estimateId, products: [{ id, price, quantity }] })
|
|
36
|
+
|
|
37
|
+
// Option B: custom line items
|
|
38
|
+
setEstimateProducts({ estimateId, products: [{ name, price, quantity }] })
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Step 3 — Wait for customer confirmation** (offline step, no API call)
|
|
42
|
+
|
|
43
|
+
**Step 4 — Approve estimate**
|
|
44
|
+
```js
|
|
45
|
+
approveEstimate({ estimateId })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Step 5 — Close other estimates for this deal**
|
|
49
|
+
```js
|
|
50
|
+
closeEstimatesForDeal({ dealId }) // closes all non-approved estimates
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Step 6 — Create smart invoice**
|
|
54
|
+
```js
|
|
55
|
+
createSmartInvoice({ dealId, contactId, companyId })
|
|
56
|
+
// → returns invoiceId
|
|
57
|
+
// Always pass BOTH contactId AND companyId — no payer = template broken
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Step 7 — Set invoice products (pick ONE method only)**
|
|
61
|
+
```js
|
|
62
|
+
// Method A: copy from deal (recommended when deal products are set)
|
|
63
|
+
copyDealProductsToInvoice({ dealId, invoiceId })
|
|
64
|
+
|
|
65
|
+
// Method B: set manually
|
|
66
|
+
setInvoiceProducts({ invoiceId, products: [...] })
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Verify Checklist (after invoice creation)
|
|
72
|
+
|
|
73
|
+
- [ ] Invoice `STATUS = 'N'` (new/unpaid)
|
|
74
|
+
- [ ] Payer: both `contactId` and `companyId` linked
|
|
75
|
+
- [ ] Products list matches approved estimate
|
|
76
|
+
- [ ] `OPPORTUNITY` on deal updated to match invoice total
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Common Mistakes
|
|
81
|
+
|
|
82
|
+
| Mistake | Result | Fix |
|
|
83
|
+
|---------|--------|-----|
|
|
84
|
+
| `createSmartInvoice` before `approveEstimate` | Duplicate amounts, wrong totals | Follow step order strictly |
|
|
85
|
+
| Using both `setInvoiceProducts` AND `copyDealProducts` | One overwrites the other | Pick ONE method only |
|
|
86
|
+
| Missing `contactId` or `companyId` on invoice | No payer linked → document template broken | Always pass both |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Products Discovery
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
// Search product catalog before creating estimate
|
|
94
|
+
findProducts({ query: "keyword", limit: 10 })
|
|
95
|
+
// → [{ id, name, price, currency, unit }]
|
|
96
|
+
```
|