@besales/mcp 1.0.0-beta.2 → 1.0.0-beta.5

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 (73) hide show
  1. package/README.md +14 -3
  2. package/dist/http/api-client.d.ts +10 -0
  3. package/dist/http/api-client.js +2 -1
  4. package/dist/http/api-client.js.map +1 -1
  5. package/dist/resources/concepts/triggers.md +35 -0
  6. package/dist/resources/docs/platforms.md +58 -0
  7. package/dist/schemas/mcp-tools.json +892 -40
  8. package/dist/tools/definitions/agent-design.d.ts +5 -5
  9. package/dist/tools/definitions/ai-costs.d.ts +1 -1
  10. package/dist/tools/definitions/api-tool-request.d.ts +4 -2
  11. package/dist/tools/definitions/broadcast-analytics.d.ts +1 -1
  12. package/dist/tools/definitions/crm-platform.d.ts +5 -2
  13. package/dist/tools/definitions/crm-platform.js +30 -0
  14. package/dist/tools/definitions/crm-platform.js.map +1 -1
  15. package/dist/tools/definitions/dialogue-export.d.ts +1 -1
  16. package/dist/tools/definitions/dialogue-nudge.d.ts +7 -0
  17. package/dist/tools/definitions/dialogue-nudge.js +139 -0
  18. package/dist/tools/definitions/dialogue-nudge.js.map +1 -0
  19. package/dist/tools/definitions/dialogue-reprocess.d.ts +5 -0
  20. package/dist/tools/definitions/dialogue-reprocess.js +107 -0
  21. package/dist/tools/definitions/dialogue-reprocess.js.map +1 -0
  22. package/dist/tools/definitions/follow-up.d.ts +1 -1
  23. package/dist/tools/definitions/funnel-analytics.d.ts +1 -1
  24. package/dist/tools/definitions/getcourse-cold-welcome.js +18 -7
  25. package/dist/tools/definitions/getcourse-cold-welcome.js.map +1 -1
  26. package/dist/tools/definitions/knowledge.d.ts +1 -1
  27. package/dist/tools/definitions/model-comparison.d.ts +1 -1
  28. package/dist/tools/definitions/platform-setup-wave.d.ts +1 -1
  29. package/dist/tools/definitions/platform-setup.d.ts +12 -1
  30. package/dist/tools/definitions/shared.d.ts +5 -0
  31. package/dist/tools/definitions/shared.js.map +1 -1
  32. package/dist/tools/definitions/task-state.d.ts +4 -4
  33. package/dist/tools/definitions/telegram-personal-management.d.ts +34 -0
  34. package/dist/tools/definitions/telegram-personal-management.js +139 -0
  35. package/dist/tools/definitions/telegram-personal-management.js.map +1 -0
  36. package/dist/tools/definitions/telegram-personal-profile.d.ts +24 -0
  37. package/dist/tools/definitions/telegram-personal-profile.js +154 -0
  38. package/dist/tools/definitions/telegram-personal-profile.js.map +1 -0
  39. package/dist/tools/definitions/telegram-personal-restrictions.d.ts +19 -0
  40. package/dist/tools/definitions/telegram-personal-restrictions.js +109 -0
  41. package/dist/tools/definitions/telegram-personal-restrictions.js.map +1 -0
  42. package/dist/tools/definitions/telegram-pool-policy.d.ts +1 -1
  43. package/dist/tools/definitions/trigger-upsert.tool.d.ts +12 -0
  44. package/dist/tools/definitions/trigger-upsert.tool.js +38 -1
  45. package/dist/tools/definitions/trigger-upsert.tool.js.map +1 -1
  46. package/dist/tools/definitions.d.ts +117 -25
  47. package/dist/tools/definitions.js +10 -0
  48. package/dist/tools/definitions.js.map +1 -1
  49. package/dist/tools/follow-up-request.js +3 -0
  50. package/dist/tools/follow-up-request.js.map +1 -1
  51. package/dist/tools/registry-mapping-primary.cases.js +12 -0
  52. package/dist/tools/registry-mapping-primary.cases.js.map +1 -1
  53. package/dist/tools/registry-mapping.cases.js +230 -0
  54. package/dist/tools/registry-mapping.cases.js.map +1 -1
  55. package/dist/tools/registry-test-fixtures.js +5 -1
  56. package/dist/tools/registry-test-fixtures.js.map +1 -1
  57. package/dist/tools/registry.js +3 -1
  58. package/dist/tools/registry.js.map +1 -1
  59. package/dist/types/api-contract.gen.d.ts +81138 -55369
  60. package/docs/dialogue-nudge.md +50 -0
  61. package/docs/dialogue-reprocess.md +37 -0
  62. package/docs/modules/besales-mcp.md +7 -0
  63. package/docs/telegram-personal-management.md +100 -0
  64. package/docs/telegram-personal-restrictions.md +87 -0
  65. package/package.json +1 -1
  66. package/scripts/getcourse-text-source.spec.mjs +110 -0
  67. package/scripts/shipped-sample.mjs +3 -0
  68. package/scripts/sync-trigger-argument-schema.mjs +10 -34
  69. package/scripts/sync-trigger-argument-schema.spec.mjs +91 -0
  70. package/scripts/sync-trigger-event-schema.mjs +20 -0
  71. package/scripts/sync-trigger-task-schema.mjs +45 -0
  72. package/scripts/telegram-personal-confirmation-mutants.mjs +74 -0
  73. package/scripts/telegram-personal-profile-mutants.mjs +96 -0
@@ -0,0 +1,45 @@
1
+ /** Обновляет поля внутри объекта, сохраняя nullable-обёртку и её ограничения. */
2
+ export function syncCallOperatorTaskSchema(action, canonical, callOperator) {
3
+ const config = action.properties.callOperatorConfig;
4
+ const branches = config.anyOf ?? config.oneOf;
5
+ const object = branches
6
+ ? branches.length === 2 && branches.some((branch) => branch.type === 'null')
7
+ ? branches.find((branch) => branch.type === 'object' && branch.properties)
8
+ : undefined
9
+ : config;
10
+ if (!object?.properties?.taskText || !object.properties.taskDueHours) {
11
+ throw new Error('CALL_OPERATOR_CONFIG_SCHEMA_UNEXPECTED');
12
+ }
13
+ for (const [name, alias] of [
14
+ ['task_text', 'taskText'],
15
+ ['task_due_hours', 'taskDueHours'],
16
+ ]) {
17
+ const property = callOperator.properties[name];
18
+ const nullable = property.anyOf?.some((branch) => branch.type === 'null');
19
+ const value = property.anyOf?.find((branch) => branch.type !== 'null');
20
+ const runtime = canonical.properties[name].anyOf.find((branch) => branch.type !== 'null');
21
+ // refine считает Unicode; JSON Schema maxLength считает те же кодовые точки.
22
+ if (
23
+ !nullable ||
24
+ (name === 'task_text'
25
+ ? value?.type !== 'string' || value.maxLength !== 500
26
+ : value?.type !== runtime.type ||
27
+ value.minimum !== runtime.minimum ||
28
+ value.maximum !== runtime.maximum)
29
+ ) {
30
+ throw new Error(`CALL_OPERATOR_TASK_CONTRACT_DRIFT:${name}`);
31
+ }
32
+ canonical.properties[name] = {
33
+ ...property,
34
+ description: canonical.properties[name].description,
35
+ };
36
+ object.properties[alias] = {
37
+ ...property,
38
+ description: object.properties[alias].description,
39
+ };
40
+ }
41
+ action.properties.config = {
42
+ ...action.properties.config,
43
+ properties: canonical.properties,
44
+ };
45
+ }
@@ -0,0 +1,74 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+
6
+ const suite = 'src/tools/definitions/telegram-personal-restrictions.spec.ts';
7
+ const temporary = mkdtempSync(join(tmpdir(), 'telegram-confirmation-'));
8
+ function run(pattern, name) {
9
+ const output = join(temporary, name + '.json');
10
+ const result = spawnSync(process.execPath, [
11
+ 'node_modules/vitest/vitest.mjs', 'run', suite,
12
+ '--maxWorkers=1', '--reporter=json', '--outputFile=' + output,
13
+ ...(pattern ? ['--testNamePattern', pattern] : []),
14
+ ], { encoding: 'utf8', timeout: 180000 });
15
+ const report = JSON.parse(readFileSync(output, 'utf8'));
16
+ return { result, report };
17
+ }
18
+ try {
19
+ const baseline = run(undefined, 'baseline');
20
+ if (baseline.result.status !== 0 || baseline.report.numPassedTests === 0) {
21
+ throw new Error('BASELINE_FAILED\n' + baseline.result.stdout + baseline.result.stderr);
22
+ }
23
+ console.log('BASELINE PASS ' + baseline.report.numPassedTests);
24
+ for (const entry of [
25
+ {
26
+ name: 'appeal-runtime-confirmation-optional',
27
+ file: 'src/tools/definitions/telegram-personal-restrictions.ts',
28
+ pattern: 'без явного true',
29
+ mutate: (text) => {
30
+ const anchor = 'explicit_confirmation: z\n .literal(true)';
31
+ if (text.split(anchor).length !== 2) throw new Error('MUTATION_ANCHOR_NOT_UNIQUE');
32
+ return text.replace(anchor, anchor + '.optional()');
33
+ },
34
+ },
35
+ {
36
+ name: 'appeal-published-confirmation-optional',
37
+ file: 'src/schemas/mcp-tools.json',
38
+ pattern: 'omits optional text in schema and HTTP, retaining explicit confirmation',
39
+ mutate: (text) => {
40
+ const registry = JSON.parse(text);
41
+ const schema = registry.tools.find((tool) =>
42
+ tool.name === 'besales_platform_telegram_personal_restriction_appeal',
43
+ ).inputSchema;
44
+ schema.required = schema.required.filter((field) => field !== 'explicit_confirmation');
45
+ return JSON.stringify(registry, null, 2) + '\n';
46
+ },
47
+ },
48
+ ]) {
49
+ const original = readFileSync(entry.file, 'utf8');
50
+ try {
51
+ writeFileSync(entry.file, entry.mutate(original));
52
+ const { result, report } = run(entry.pattern, entry.name);
53
+ // Убитым считается только провал утверждения внутри названного теста: AssertionError
54
+ // или отказ vitest expect(...).rejects («promise resolved … instead of rejecting»).
55
+ // Ошибка загрузки набора не даёт assertionResults и остаётся INFRA_FAILURE.
56
+ const failures = report.testResults.flatMap((item) => item.assertionResults).filter((test) =>
57
+ test.status === 'failed' && test.fullName.includes(entry.pattern) &&
58
+ test.failureMessages.some(
59
+ (message) =>
60
+ message.includes('AssertionError') ||
61
+ /^Error: promise resolved .* instead of rejecting/su.test(message),
62
+ ),
63
+ );
64
+ if (result.status === 0 || result.signal || failures.length === 0) {
65
+ throw new Error('SURVIVED_OR_INFRA_FAILURE:' + entry.name + '\n' + result.stdout + result.stderr);
66
+ }
67
+ console.log('KILLED ' + entry.name + ' ' + JSON.stringify(failures.map((test) => test.fullName)));
68
+ } finally {
69
+ writeFileSync(entry.file, original);
70
+ }
71
+ }
72
+ } finally {
73
+ rmSync(temporary, { recursive: true, force: true });
74
+ }
@@ -0,0 +1,96 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+
6
+ const suite = 'src/tools/definitions/telegram-personal-profile.spec.ts';
7
+ const tool = 'src/tools/definitions/telegram-personal-profile.ts';
8
+ const published = 'src/schemas/mcp-tools.json';
9
+ const temporary = mkdtempSync(join(tmpdir(), 'telegram-profile-mutants-'));
10
+ function run(pattern, name) {
11
+ const output = join(temporary, name + '.json');
12
+ const result = spawnSync(process.execPath, [
13
+ 'node_modules/vitest/vitest.mjs', 'run', suite,
14
+ '--maxWorkers=1', '--reporter=json', '--outputFile=' + output,
15
+ ...(pattern ? ['--testNamePattern', pattern] : []),
16
+ ], { encoding: 'utf8', timeout: 180000 });
17
+ const report = JSON.parse(readFileSync(output, 'utf8'));
18
+ return { result, report };
19
+ }
20
+ // Единственное вхождение якоря: иначе мутация могла бы тихо попасть не туда.
21
+ function replaceOnce(text, anchor, replacement) {
22
+ if (text.split(anchor).length !== 2) throw new Error('MUTATION_ANCHOR_NOT_UNIQUE');
23
+ return text.replace(anchor, replacement);
24
+ }
25
+ try {
26
+ const baseline = run(undefined, 'baseline');
27
+ if (baseline.result.status !== 0 || baseline.report.numPassedTests === 0) {
28
+ throw new Error('BASELINE_FAILED\n' + baseline.result.stdout + baseline.result.stderr);
29
+ }
30
+ console.log('BASELINE PASS ' + baseline.report.numPassedTests);
31
+ for (const entry of [
32
+ {
33
+ // Главный мутант пачки: оба режима ников разрешены одновременно в Zod-схеме инструмента.
34
+ name: 'username-modes-both-allowed-runtime',
35
+ file: tool,
36
+ pattern: 'оба режима сразу отвергаются до HTTP',
37
+ mutate: (text) =>
38
+ replaceOnce(
39
+ text,
40
+ " if (input.username_base !== undefined) {\n refuse(\n 'username_base',",
41
+ " if (input.username_base !== undefined && false) {\n refuse(\n 'username_base',",
42
+ ),
43
+ },
44
+ {
45
+ // То же в опубликованной схеме: снят запрет «usernames вместе с username_base».
46
+ name: 'username-modes-both-allowed-published',
47
+ file: published,
48
+ pattern: 'оба режима сразу отвергаются до HTTP',
49
+ mutate: (text) => {
50
+ const registry = JSON.parse(text);
51
+ const schema = registry.tools.find(
52
+ (item) => item.name === 'besales_platform_telegram_personal_profile_bulk',
53
+ ).inputSchema;
54
+ const before = schema.allOf.length;
55
+ schema.allOf = schema.allOf.filter(
56
+ (rule) => !(rule.not?.required?.includes('usernames') && rule.not.required.includes('username_base')),
57
+ );
58
+ if (schema.allOf.length !== before - 1) throw new Error('MUTATION_ANCHOR_NOT_UNIQUE');
59
+ return JSON.stringify(registry, null, 2) + '\n';
60
+ },
61
+ },
62
+ {
63
+ // Ключ идемпотентности уходит под общим именем, которого профильный маршрут ядра не читает.
64
+ name: 'idempotency-key-default-header',
65
+ file: tool,
66
+ pattern: 'идёт заголовком x-idempotency-key',
67
+ mutate: (text) =>
68
+ replaceOnce(text, " idempotencyKeyHeader: 'X-Idempotency-Key',\n", ''),
69
+ },
70
+ ]) {
71
+ const original = readFileSync(entry.file, 'utf8');
72
+ try {
73
+ writeFileSync(entry.file, entry.mutate(original));
74
+ const { result, report } = run(entry.pattern, entry.name);
75
+ // Убитым считается только провал утверждения внутри названного теста: AssertionError
76
+ // или отказ vitest expect(...).rejects («promise resolved … instead of rejecting»).
77
+ // Ошибка загрузки набора не даёт assertionResults и остаётся INFRA_FAILURE.
78
+ const failures = report.testResults.flatMap((item) => item.assertionResults).filter((test) =>
79
+ test.status === 'failed' && test.fullName.includes(entry.pattern) &&
80
+ test.failureMessages.some(
81
+ (message) =>
82
+ message.includes('AssertionError') ||
83
+ /^Error: promise resolved .* instead of rejecting/su.test(message),
84
+ ),
85
+ );
86
+ if (result.status === 0 || result.signal || failures.length === 0) {
87
+ throw new Error('SURVIVED_OR_INFRA_FAILURE:' + entry.name + '\n' + result.stdout + result.stderr);
88
+ }
89
+ console.log('KILLED ' + entry.name + ' ' + JSON.stringify(failures.map((test) => test.fullName)));
90
+ } finally {
91
+ writeFileSync(entry.file, original);
92
+ }
93
+ }
94
+ } finally {
95
+ rmSync(temporary, { recursive: true, force: true });
96
+ }