@besales/mcp 1.0.0-beta.7 → 1.0.0-beta.9

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 (72) hide show
  1. package/README.md +41 -6
  2. package/dist/auth/oauth-client.d.ts +1 -1
  3. package/dist/auth/oauth-client.js +2 -0
  4. package/dist/auth/oauth-client.js.map +1 -1
  5. package/dist/resources/concepts/sandbox.md +8 -1
  6. package/dist/resources/concepts/triggers.md +1 -0
  7. package/dist/resources/docs/platforms.md +10 -1
  8. package/dist/resources/docs/trigger-actions.md +24 -0
  9. package/dist/resources/workflows/iterate-with-sandbox.md +6 -2
  10. package/dist/resources/workflows/platform-setup-from-scratch.md +27 -0
  11. package/dist/schemas/mcp-tools.json +360 -12
  12. package/dist/tools/definitions/agent-design.d.ts +1 -1
  13. package/dist/tools/definitions/agent-design.js +13 -7
  14. package/dist/tools/definitions/agent-design.js.map +1 -1
  15. package/dist/tools/definitions/broadcast-analytics.js +1 -1
  16. package/dist/tools/definitions/broadcast-analytics.js.map +1 -1
  17. package/dist/tools/definitions/broadcast-campaigns.d.ts +29 -0
  18. package/dist/tools/definitions/broadcast-campaigns.js +107 -0
  19. package/dist/tools/definitions/broadcast-campaigns.js.map +1 -0
  20. package/dist/tools/definitions/dialogue-export.js +2 -0
  21. package/dist/tools/definitions/dialogue-export.js.map +1 -1
  22. package/dist/tools/definitions/follow-up.d.ts +1 -1
  23. package/dist/tools/definitions/platform-setup-wave.d.ts +1 -1
  24. package/dist/tools/definitions/platform-setup.d.ts +11 -1
  25. package/dist/tools/definitions/telegram-outreach-calendar.d.ts +17 -0
  26. package/dist/tools/definitions/telegram-outreach-calendar.js +68 -0
  27. package/dist/tools/definitions/telegram-outreach-calendar.js.map +1 -0
  28. package/dist/tools/definitions/telegram-personal-profile.d.ts +2 -0
  29. package/dist/tools/definitions/telegram-personal-profile.js +14 -0
  30. package/dist/tools/definitions/telegram-personal-profile.js.map +1 -1
  31. package/dist/tools/definitions/telegram-session-import.d.ts +5 -0
  32. package/dist/tools/definitions/telegram-session-import.js +33 -0
  33. package/dist/tools/definitions/telegram-session-import.js.map +1 -0
  34. package/dist/tools/definitions/trigger-action-item.schema.d.ts +10 -0
  35. package/dist/tools/definitions/trigger-action-item.schema.js +28 -11
  36. package/dist/tools/definitions/trigger-action-item.schema.js.map +1 -1
  37. package/dist/tools/definitions/trigger-upsert.tool.d.ts +1 -0
  38. package/dist/tools/definitions/trigger-upsert.tool.js +13 -0
  39. package/dist/tools/definitions/trigger-upsert.tool.js.map +1 -1
  40. package/dist/tools/definitions.d.ts +48 -6
  41. package/dist/tools/definitions.js +6 -0
  42. package/dist/tools/definitions.js.map +1 -1
  43. package/dist/tools/registry-mapping.cases.js +133 -93
  44. package/dist/tools/registry-mapping.cases.js.map +1 -1
  45. package/dist/tools/registry.js +10 -11
  46. package/dist/tools/registry.js.map +1 -1
  47. package/dist/tools/result.d.ts +1 -1
  48. package/dist/tools/result.js +60 -39
  49. package/dist/tools/result.js.map +1 -1
  50. package/dist/types/api-contract.gen.d.ts +2220 -216
  51. package/docs/async-operation-lifecycle.md +13 -2
  52. package/docs/failure-semantics.md +11 -1
  53. package/docs/secret-read-boundary.md +7 -0
  54. package/docs/telegram-personal-management.md +66 -22
  55. package/docs/telegram-session-import.md +53 -0
  56. package/package.json +8 -7
  57. package/scripts/body-idempotency-contract.mjs +95 -0
  58. package/scripts/generate-followup-session-contract.mjs +14 -7
  59. package/scripts/generated-output.mjs +9 -0
  60. package/scripts/sync-agent-model-schemas.mjs +11 -11
  61. package/scripts/sync-api-contracts.mjs +99 -40
  62. package/scripts/sync-crm-stage-pool-schema.mjs +6 -7
  63. package/scripts/sync-route-map.mjs +189 -35
  64. package/scripts/sync-sandbox-request-key.mjs +40 -0
  65. package/scripts/sync-telegram-profile-photo.mjs +57 -0
  66. package/scripts/sync-telegram-session-import.mjs +39 -0
  67. package/scripts/sync-tool-inventory.mjs +15 -7
  68. package/scripts/sync-trigger-argument-schema.mjs +31 -14
  69. package/scripts/sync-trigger-event-schema.mjs +11 -6
  70. package/scripts/sync-trigger-step-reference-schema.mjs +21 -0
  71. package/scripts/sync-wave-id-schemas.mjs +7 -6
  72. package/scripts/telegram-personal-profile-mutants.mjs +59 -18
@@ -1,9 +1,13 @@
1
- import { readFileSync, writeFileSync } from 'node:fs';
1
+ import { writeGeneratedFile } from './generated-output.mjs';
2
+ import { readFileSync } from 'node:fs';
2
3
  import ts from 'typescript';
3
4
 
4
5
  const source = readFileSync(new URL('../src/tools/inventory.ts', import.meta.url), 'utf8');
5
6
  const compiled = ts.transpileModule(source, {
6
- compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 },
7
+ compilerOptions: {
8
+ module: ts.ModuleKind.ESNext,
9
+ target: ts.ScriptTarget.ES2022,
10
+ },
7
11
  }).outputText;
8
12
  const { renderToolInventoryMarkdown, toolInventoryCounts } = await import(
9
13
  'data:text/javascript;base64,' + Buffer.from(compiled).toString('base64')
@@ -13,15 +17,19 @@ const schema = JSON.parse(readFileSync(schemaUrl, 'utf8'));
13
17
  const names = schema.tools.filter((tool) => tool.status !== 'removed').map((tool) => tool.name);
14
18
  schema.summary.total_tools = names.length;
15
19
  schema.summary.tools_by_category = toolInventoryCounts(names);
16
- writeFileSync(schemaUrl, JSON.stringify(schema, null, 2) + '\n');
20
+ writeGeneratedFile(schemaUrl, JSON.stringify(schema, null, 2) + '\n');
17
21
  const readmeUrl = new URL('../README.md', import.meta.url);
18
22
  const readme = readFileSync(readmeUrl, 'utf8');
19
23
  const begin = '<!-- BEGIN GENERATED TOOL INVENTORY -->';
20
24
  const end = '<!-- END GENERATED TOOL INVENTORY -->';
21
- const first = readme.indexOf(begin), last = readme.indexOf(end);
25
+ const first = readme.indexOf(begin),
26
+ last = readme.indexOf(end);
22
27
  if (first < 0 || last < first) throw new Error('README inventory markers missing');
23
- writeFileSync(
28
+ writeGeneratedFile(
24
29
  readmeUrl,
25
- readme.slice(0, first + begin.length) + '\n\n' +
26
- renderToolInventoryMarkdown(names) + '\n\n' + readme.slice(last),
30
+ readme.slice(0, first + begin.length) +
31
+ '\n\n' +
32
+ renderToolInventoryMarkdown(names) +
33
+ '\n\n' +
34
+ readme.slice(last),
27
35
  );
@@ -1,13 +1,15 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
1
+ import { writeGeneratedFile } from './generated-output.mjs';
2
+ import { readFileSync } from 'node:fs';
2
3
  import { resolve } from 'node:path';
3
4
  import { pathToFileURL } from 'node:url';
4
5
  import openapiTS from 'openapi-typescript';
5
6
  import { z } from 'zod';
6
- import { linkTrackingTools } from '../dist/tools/definitions/link-tracking.js';
7
- import { triggerActionArgumentSchema } from '../dist/tools/definitions/trigger-argument.schema.js';
8
- import { toolDefinitions } from '../dist/tools/definitions.js';
9
- import { triggerActionItemSchema } from '../dist/tools/definitions/platform-setup.js';
10
- import { canonicalCallOperatorTaskSchema } from '../dist/tools/definitions/call-operator-task.schema.js';
7
+ import { linkTrackingTools } from '../src/tools/definitions/link-tracking.js';
8
+ import { triggerActionArgumentSchema } from '../src/tools/definitions/trigger-argument.schema.js';
9
+ import { toolDefinitions } from '../src/tools/definitions.js';
10
+ import { triggerActionItemSchema } from '../src/tools/definitions/platform-setup.js';
11
+ import { canonicalCallOperatorTaskSchema } from '../src/tools/definitions/call-operator-task.schema.js';
12
+ import { stagePoolFields } from '../src/tools/definitions/crm-stage-pool.schema.js';
11
13
  import { syncCallOperatorTaskSchema } from './sync-trigger-task-schema.mjs';
12
14
 
13
15
  // Границы опубликованных полей — из контракта выбранного API checkout, не из ручного JSON.
@@ -54,7 +56,10 @@ for (const [name, field] of [
54
56
  delete published.$schema;
55
57
  tool.inputSchema.properties[field] = published;
56
58
  }
57
- const argument = z.toJSONSchema(triggerActionArgumentSchema, { target: 'draft-7', io: 'input' });
59
+ const argument = z.toJSONSchema(triggerActionArgumentSchema, {
60
+ target: 'draft-7',
61
+ io: 'input',
62
+ });
58
63
  delete argument.$schema;
59
64
  for (const name of ['besales_trigger_upsert']) {
60
65
  const tool = registry.tools.find((entry) => entry.name === name);
@@ -65,14 +70,25 @@ for (const name of ['besales_trigger_upsert']) {
65
70
  throw new Error(`TRIGGER_ACTION_SCHEMA_MISSING:${name}`);
66
71
  const publishedAction = tool.inputSchema.properties.actions.items;
67
72
  publishedAction.properties.callOperatorConfig = action.properties.callOperatorConfig;
68
- publishedAction.properties.config = action.properties.config;
73
+ const poolProperties = Object.fromEntries(
74
+ [...Object.keys(stagePoolFields), 'extra']
75
+ .filter((field) => publishedAction.properties.config.properties[field] !== undefined)
76
+ .map((field) => [field, publishedAction.properties.config.properties[field]]),
77
+ );
78
+ publishedAction.properties.config = {
79
+ ...action.properties.config,
80
+ properties: { ...action.properties.config.properties, ...poolProperties },
81
+ };
69
82
  }
70
83
  // Поля каталога публикуются из исполняемой схемы: null очистки и refine входят в носитель.
71
84
  for (const name of ['besales_tracked_link_create', 'besales_tracked_link_update']) {
72
85
  const definition = linkTrackingTools.find((entry) => entry.name === name);
73
86
  const tool = registry.tools.find((entry) => entry.name === name);
74
87
  if (!definition || !tool) throw new Error(`LINK_CATALOG_SCHEMA_MISSING:${name}`);
75
- const derived = z.toJSONSchema(definition.schema, { target: 'draft-7', io: 'input' });
88
+ const derived = z.toJSONSchema(definition.schema, {
89
+ target: 'draft-7',
90
+ io: 'input',
91
+ });
76
92
  delete derived.$schema;
77
93
  if (!derived.properties?.personal_url_variable)
78
94
  throw new Error(`PERSONAL_URL_SCHEMA_MISSING:${name}`);
@@ -86,12 +102,13 @@ for (const name of ['besales_tracked_link_create', 'besales_tracked_link_update'
86
102
  throw new Error(`PERSONAL_URL_NULLABLE_SCHEMA_UNEXPECTED:${name}`);
87
103
  }
88
104
  // Отгруженная форма сохраняет ограничения строки и отдельное разрешение очистки через null.
89
- personalUrlVariable = { ...anyOf[0], ...metadata, type: ['string', 'null'] };
105
+ personalUrlVariable = {
106
+ ...anyOf[0],
107
+ ...metadata,
108
+ type: ['string', 'null'],
109
+ };
90
110
  }
91
111
  tool.inputSchema.properties.personal_url_variable = personalUrlVariable;
92
112
  }
93
113
  const serialized = `${JSON.stringify(registry, null, 2)}\n`;
94
- writeFileSync(target, serialized);
95
- // Уже собранный пакет и публикуемый исходник обязаны рекламировать одинаковые ограничения.
96
- mkdirSync(new URL('../dist/schemas/', import.meta.url), { recursive: true });
97
- writeFileSync(new URL('../dist/schemas/mcp-tools.json', import.meta.url), serialized);
114
+ writeGeneratedFile(target, serialized);
@@ -1,6 +1,7 @@
1
+ import { writeGeneratedFile } from './generated-output.mjs';
1
2
  // Точечный вариант sync-api-contracts: только схема и описание событийного триггера.
2
3
  // Сохраняет ручные ограничения и все прочие инструменты; типы и маршруты уже актуальны.
3
- import { readFileSync, writeFileSync } from 'node:fs';
4
+ import { readFileSync } from 'node:fs';
4
5
  import { z } from 'zod';
5
6
  import { toolDefinitions } from '../src/tools/definitions.ts';
6
7
  import { eventTriggerDescription } from '../src/tools/definitions/trigger-upsert.tool.ts';
@@ -9,12 +10,16 @@ import { syncSchemaDescriptions } from './sync-schema-descriptions.mjs';
9
10
  const registryPath = new URL('../src/schemas/mcp-tools.json', import.meta.url);
10
11
  const registry = JSON.parse(readFileSync(registryPath, 'utf8'));
11
12
  const name = 'besales_trigger_upsert';
12
- const definition = toolDefinitions.find(tool => tool.name === name);
13
- const tool = registry.tools.find(tool => tool.name === name);
13
+ const definition = toolDefinitions.find((tool) => tool.name === name);
14
+ const tool = registry.tools.find((tool) => tool.name === name);
14
15
  if (!definition || !tool) throw new Error(`REGISTRY_TOOL_MISSING:${name}`);
15
- const derived = z.toJSONSchema(definition.schema, { io: 'input', unrepresentable: 'any' });
16
+ const derived = z.toJSONSchema(definition.schema, {
17
+ io: 'input',
18
+ unrepresentable: 'any',
19
+ });
16
20
  if (!derived.properties?.trigger) throw new Error('EVENT_TRIGGER_SCHEMA_MISSING');
17
21
  tool.inputSchema.properties.trigger = derived.properties.trigger;
18
22
  syncSchemaDescriptions(tool.inputSchema, derived);
19
- if (!tool.description.includes(eventTriggerDescription)) tool.description += ' ' + eventTriggerDescription;
20
- writeFileSync(registryPath, JSON.stringify(registry, null, 2) + '\n');
23
+ if (!tool.description.includes(eventTriggerDescription))
24
+ tool.description += ' ' + eventTriggerDescription;
25
+ writeGeneratedFile(registryPath, JSON.stringify(registry, null, 2) + '\n');
@@ -0,0 +1,21 @@
1
+ import { writeGeneratedFile } from './generated-output.mjs';
2
+ // Пересобирает только вход ссылок, сохраняя ручные ограничения остальных полей реестра.
3
+ import { readFileSync } from 'node:fs';
4
+ import { z } from 'zod';
5
+ import { triggerSetupActionItemSchema } from '../src/tools/definitions/trigger-action-item.schema.ts';
6
+ import { editOneStepDescription } from '../src/tools/definitions/trigger-upsert.tool.ts';
7
+
8
+ const target = new URL('../src/schemas/mcp-tools.json', import.meta.url);
9
+ const registry = JSON.parse(readFileSync(target, 'utf8'));
10
+ const tool = registry.tools.find((item) => item.name === 'besales_trigger_upsert');
11
+ const derived = z.toJSONSchema(triggerSetupActionItemSchema, {
12
+ io: 'input',
13
+ unrepresentable: 'any',
14
+ });
15
+ if (!tool?.inputSchema.properties.actions.items.properties || !derived.properties?.stepId)
16
+ throw new Error('TRIGGER_STEP_REFERENCE_SCHEMA_MISSING');
17
+ for (const field of ['stepId', 'onError', 'stopOnSuccess'])
18
+ tool.inputSchema.properties.actions.items.properties[field] = derived.properties[field];
19
+ if (!tool.description.includes(editOneStepDescription))
20
+ tool.description += ' ' + editOneStepDescription;
21
+ writeGeneratedFile(target, JSON.stringify(registry, null, 2) + '\n');
@@ -1,7 +1,8 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
1
+ import { writeGeneratedFile } from './generated-output.mjs';
2
+ import { readFileSync } from 'node:fs';
2
3
  import { z } from 'zod';
3
4
 
4
- import { platformSetupWaveTools } from '../dist/tools/definitions/platform-setup-wave.js';
5
+ import { platformSetupWaveTools } from '../src/tools/definitions/platform-setup-wave.js';
5
6
 
6
7
  // Ограничения берутся из исполняемых схем; подписи объясняют номера без имён таблиц.
7
8
  const numericPaths = {
@@ -46,10 +47,10 @@ for (const [name, paths] of Object.entries(numericPaths)) {
46
47
  throw new Error(`WAVE_ID_SCHEMA_MISSING:${name}:${path.join('.')}`);
47
48
  }
48
49
  for (const key of Object.keys(published)) delete published[key];
49
- Object.assign(published, executable, { description: descriptions[path.at(-1)] });
50
+ Object.assign(published, executable, {
51
+ description: descriptions[path.at(-1)],
52
+ });
50
53
  }
51
54
  }
52
55
  const serialized = `${JSON.stringify(registry, null, 2)}\n`;
53
- writeFileSync(target, serialized);
54
- mkdirSync(new URL('../dist/schemas/', import.meta.url), { recursive: true });
55
- writeFileSync(new URL('../dist/schemas/mcp-tools.json', import.meta.url), serialized);
56
+ writeGeneratedFile(target, serialized);
@@ -9,11 +9,19 @@ const published = 'src/schemas/mcp-tools.json';
9
9
  const temporary = mkdtempSync(join(tmpdir(), 'telegram-profile-mutants-'));
10
10
  function run(pattern, name) {
11
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 });
12
+ const result = spawnSync(
13
+ process.execPath,
14
+ [
15
+ 'node_modules/vitest/vitest.mjs',
16
+ 'run',
17
+ suite,
18
+ '--maxWorkers=1',
19
+ '--reporter=json',
20
+ '--outputFile=' + output,
21
+ ...(pattern ? ['--testNamePattern', pattern] : []),
22
+ ],
23
+ { encoding: 'utf8', timeout: 180000 },
24
+ );
17
25
  const report = JSON.parse(readFileSync(output, 'utf8'));
18
26
  return { result, report };
19
27
  }
@@ -29,6 +37,28 @@ try {
29
37
  }
30
38
  console.log('BASELINE PASS ' + baseline.report.numPassedTests);
31
39
  for (const entry of [
40
+ {
41
+ name: 'photo-mapping-removed',
42
+ file: tool,
43
+ pattern: 'одно фото из stored_file_id уходит выбранным номерам',
44
+ mutate: (text) => replaceOnce(text, ' avatar: input.stored_file_id,\n', ''),
45
+ },
46
+ {
47
+ name: 'photo-not-counted-as-change-published',
48
+ file: published,
49
+ pattern: 'одно фото из stored_file_id уходит выбранным номерам',
50
+ mutate: (text) => {
51
+ const registry = JSON.parse(text);
52
+ const schema = registry.tools.find(
53
+ (item) => item.name === 'besales_platform_telegram_personal_profile_bulk',
54
+ ).inputSchema;
55
+ const rule = schema.allOf.find((item) => item.anyOf);
56
+ const before = rule.anyOf.length;
57
+ rule.anyOf = rule.anyOf.filter((item) => !item.required?.includes('stored_file_id'));
58
+ if (rule.anyOf.length !== before - 1) throw new Error('MUTATION_ANCHOR_NOT_UNIQUE');
59
+ return JSON.stringify(registry, null, 2) + '\n';
60
+ },
61
+ },
32
62
  {
33
63
  // Главный мутант пачки: оба режима ников разрешены одновременно в Zod-схеме инструмента.
34
64
  name: 'username-modes-both-allowed-runtime',
@@ -53,7 +83,11 @@ try {
53
83
  ).inputSchema;
54
84
  const before = schema.allOf.length;
55
85
  schema.allOf = schema.allOf.filter(
56
- (rule) => !(rule.not?.required?.includes('usernames') && rule.not.required.includes('username_base')),
86
+ (rule) =>
87
+ !(
88
+ rule.not?.required?.includes('usernames') &&
89
+ rule.not.required.includes('username_base')
90
+ ),
57
91
  );
58
92
  if (schema.allOf.length !== before - 1) throw new Error('MUTATION_ANCHOR_NOT_UNIQUE');
59
93
  return JSON.stringify(registry, null, 2) + '\n';
@@ -64,8 +98,7 @@ try {
64
98
  name: 'idempotency-key-default-header',
65
99
  file: tool,
66
100
  pattern: 'идёт заголовком x-idempotency-key',
67
- mutate: (text) =>
68
- replaceOnce(text, " idempotencyKeyHeader: 'X-Idempotency-Key',\n", ''),
101
+ mutate: (text) => replaceOnce(text, " idempotencyKeyHeader: 'X-Idempotency-Key',\n", ''),
69
102
  },
70
103
  ]) {
71
104
  const original = readFileSync(entry.file, 'utf8');
@@ -75,18 +108,26 @@ try {
75
108
  // Убитым считается только провал утверждения внутри названного теста: AssertionError
76
109
  // или отказ vitest expect(...).rejects («promise resolved … instead of rejecting»).
77
110
  // Ошибка загрузки набора не даёт 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
- );
111
+ const failures = report.testResults
112
+ .flatMap((item) => item.assertionResults)
113
+ .filter(
114
+ (test) =>
115
+ test.status === 'failed' &&
116
+ test.fullName.includes(entry.pattern) &&
117
+ test.failureMessages.some(
118
+ (message) =>
119
+ message.includes('AssertionError') ||
120
+ /^Error: promise resolved .* instead of rejecting/su.test(message),
121
+ ),
122
+ );
86
123
  if (result.status === 0 || result.signal || failures.length === 0) {
87
- throw new Error('SURVIVED_OR_INFRA_FAILURE:' + entry.name + '\n' + result.stdout + result.stderr);
124
+ throw new Error(
125
+ 'SURVIVED_OR_INFRA_FAILURE:' + entry.name + '\n' + result.stdout + result.stderr,
126
+ );
88
127
  }
89
- console.log('KILLED ' + entry.name + ' ' + JSON.stringify(failures.map((test) => test.fullName)));
128
+ console.log(
129
+ 'KILLED ' + entry.name + ' ' + JSON.stringify(failures.map((test) => test.fullName)),
130
+ );
90
131
  } finally {
91
132
  writeFileSync(entry.file, original);
92
133
  }