huly-mcp-selfhost 2.1.0 → 3.2.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 (200) hide show
  1. package/.env.example +39 -2
  2. package/README.md +462 -16
  3. package/dist/connection.d.ts +8 -0
  4. package/dist/connection.js +13 -1
  5. package/dist/connection.js.map +1 -1
  6. package/dist/env.d.ts +1 -0
  7. package/dist/env.js +17 -0
  8. package/dist/env.js.map +1 -0
  9. package/dist/guard.d.ts +28 -0
  10. package/dist/guard.js +152 -0
  11. package/dist/guard.js.map +1 -0
  12. package/dist/guides/costs.md +48 -0
  13. package/dist/guides/features.md +49 -0
  14. package/dist/guides/onboarding.md +56 -0
  15. package/dist/guides/workflow.md +57 -0
  16. package/dist/index.js +18 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/junit-cli.d.ts +8 -0
  19. package/dist/junit-cli.js +106 -0
  20. package/dist/junit-cli.js.map +1 -0
  21. package/dist/registry.d.ts +18 -0
  22. package/dist/registry.js +318 -0
  23. package/dist/registry.js.map +1 -0
  24. package/dist/resources.d.ts +12 -0
  25. package/dist/resources.js +212 -0
  26. package/dist/resources.js.map +1 -0
  27. package/dist/schemas.d.ts +1269 -17
  28. package/dist/schemas.js +890 -97
  29. package/dist/schemas.js.map +1 -1
  30. package/dist/server.d.ts +27 -1
  31. package/dist/server.js +197 -128
  32. package/dist/server.js.map +1 -1
  33. package/dist/tools/activity.d.ts +10 -0
  34. package/dist/tools/activity.js +62 -0
  35. package/dist/tools/activity.js.map +1 -0
  36. package/dist/tools/agent.d.ts +156 -0
  37. package/dist/tools/agent.js +523 -0
  38. package/dist/tools/agent.js.map +1 -0
  39. package/dist/tools/attachments.d.ts +4 -4
  40. package/dist/tools/calendar.d.ts +49 -0
  41. package/dist/tools/calendar.js +116 -0
  42. package/dist/tools/calendar.js.map +1 -0
  43. package/dist/tools/cards.d.ts +87 -0
  44. package/dist/tools/cards.js +246 -0
  45. package/dist/tools/cards.js.map +1 -0
  46. package/dist/tools/channels.d.ts +76 -7
  47. package/dist/tools/channels.js +86 -5
  48. package/dist/tools/channels.js.map +1 -1
  49. package/dist/tools/comments.d.ts +16 -4
  50. package/dist/tools/comments.js +26 -9
  51. package/dist/tools/comments.js.map +1 -1
  52. package/dist/tools/components.d.ts +5 -5
  53. package/dist/tools/components.js +4 -22
  54. package/dist/tools/components.js.map +1 -1
  55. package/dist/tools/contacts.d.ts +69 -0
  56. package/dist/tools/contacts.js +130 -0
  57. package/dist/tools/contacts.js.map +1 -0
  58. package/dist/tools/crm.d.ts +61 -0
  59. package/dist/tools/crm.js +117 -0
  60. package/dist/tools/crm.js.map +1 -0
  61. package/dist/tools/documents.d.ts +35 -12
  62. package/dist/tools/documents.js +107 -22
  63. package/dist/tools/documents.js.map +1 -1
  64. package/dist/tools/drive.d.ts +107 -0
  65. package/dist/tools/drive.js +277 -0
  66. package/dist/tools/drive.js.map +1 -0
  67. package/dist/tools/fields.d.ts +33 -0
  68. package/dist/tools/fields.js +124 -0
  69. package/dist/tools/fields.js.map +1 -0
  70. package/dist/tools/generic.d.ts +72 -0
  71. package/dist/tools/generic.js +242 -0
  72. package/dist/tools/generic.js.map +1 -0
  73. package/dist/tools/github.d.ts +21 -0
  74. package/dist/tools/github.js +80 -0
  75. package/dist/tools/github.js.map +1 -0
  76. package/dist/tools/hr.d.ts +97 -0
  77. package/dist/tools/hr.js +150 -0
  78. package/dist/tools/hr.js.map +1 -0
  79. package/dist/tools/inbox.d.ts +23 -0
  80. package/dist/tools/inbox.js +76 -0
  81. package/dist/tools/inbox.js.map +1 -0
  82. package/dist/tools/inventory.d.ts +61 -0
  83. package/dist/tools/inventory.js +103 -0
  84. package/dist/tools/inventory.js.map +1 -0
  85. package/dist/tools/issues.d.ts +63 -12
  86. package/dist/tools/issues.js +259 -48
  87. package/dist/tools/issues.js.map +1 -1
  88. package/dist/tools/labels.d.ts +52 -4
  89. package/dist/tools/labels.js +86 -4
  90. package/dist/tools/labels.js.map +1 -1
  91. package/dist/tools/log-time.d.ts +15 -1
  92. package/dist/tools/log-time.js +70 -6
  93. package/dist/tools/log-time.js.map +1 -1
  94. package/dist/tools/meetings.d.ts +30 -0
  95. package/dist/tools/meetings.js +78 -0
  96. package/dist/tools/meetings.js.map +1 -0
  97. package/dist/tools/members.d.ts +1 -1
  98. package/dist/tools/members.js +17 -1
  99. package/dist/tools/members.js.map +1 -1
  100. package/dist/tools/message-templates.d.ts +54 -0
  101. package/dist/tools/message-templates.js +88 -0
  102. package/dist/tools/message-templates.js.map +1 -0
  103. package/dist/tools/milestones.d.ts +9 -9
  104. package/dist/tools/organizations.d.ts +5 -5
  105. package/dist/tools/organizations.js +2 -1
  106. package/dist/tools/organizations.js.map +1 -1
  107. package/dist/tools/overview.d.ts +55 -0
  108. package/dist/tools/overview.js +395 -0
  109. package/dist/tools/overview.js.map +1 -0
  110. package/dist/tools/planner.d.ts +60 -0
  111. package/dist/tools/planner.js +145 -0
  112. package/dist/tools/planner.js.map +1 -0
  113. package/dist/tools/process.d.ts +50 -0
  114. package/dist/tools/process.js +137 -0
  115. package/dist/tools/process.js.map +1 -0
  116. package/dist/tools/products.d.ts +17 -0
  117. package/dist/tools/products.js +45 -0
  118. package/dist/tools/products.js.map +1 -0
  119. package/dist/tools/projects.d.ts +17 -4
  120. package/dist/tools/projects.js +31 -2
  121. package/dist/tools/projects.js.map +1 -1
  122. package/dist/tools/qms.d.ts +57 -0
  123. package/dist/tools/qms.js +171 -0
  124. package/dist/tools/qms.js.map +1 -0
  125. package/dist/tools/recruiting.d.ts +112 -0
  126. package/dist/tools/recruiting.js +203 -0
  127. package/dist/tools/recruiting.js.map +1 -0
  128. package/dist/tools/relations.d.ts +45 -3
  129. package/dist/tools/relations.js +128 -39
  130. package/dist/tools/relations.js.map +1 -1
  131. package/dist/tools/search.d.ts +14 -1
  132. package/dist/tools/search.js +29 -1
  133. package/dist/tools/search.js.map +1 -1
  134. package/dist/tools/sharing.d.ts +62 -0
  135. package/dist/tools/sharing.js +149 -0
  136. package/dist/tools/sharing.js.map +1 -0
  137. package/dist/tools/statuses.d.ts +3 -3
  138. package/dist/tools/surveys.d.ts +22 -0
  139. package/dist/tools/surveys.js +53 -0
  140. package/dist/tools/surveys.js.map +1 -0
  141. package/dist/tools/templates.d.ts +95 -0
  142. package/dist/tools/templates.js +260 -0
  143. package/dist/tools/templates.js.map +1 -0
  144. package/dist/tools/test-automation.d.ts +81 -0
  145. package/dist/tools/test-automation.js +225 -0
  146. package/dist/tools/test-automation.js.map +1 -0
  147. package/dist/tools/testing.d.ts +234 -0
  148. package/dist/tools/testing.js +401 -0
  149. package/dist/tools/testing.js.map +1 -0
  150. package/dist/tools/workspace-admin.d.ts +55 -0
  151. package/dist/tools/workspace-admin.js +117 -0
  152. package/dist/tools/workspace-admin.js.map +1 -0
  153. package/dist/tools/workspaces.d.ts +1 -1
  154. package/dist/utils/attributes.d.ts +37 -0
  155. package/dist/utils/attributes.js +188 -0
  156. package/dist/utils/attributes.js.map +1 -0
  157. package/dist/utils/classes.d.ts +51 -0
  158. package/dist/utils/classes.js +73 -0
  159. package/dist/utils/classes.js.map +1 -0
  160. package/dist/utils/content.d.ts +11 -0
  161. package/dist/utils/content.js +86 -0
  162. package/dist/utils/content.js.map +1 -0
  163. package/dist/utils/errors.js +1 -1
  164. package/dist/utils/errors.js.map +1 -1
  165. package/dist/utils/files.d.ts +5 -0
  166. package/dist/utils/files.js +50 -0
  167. package/dist/utils/files.js.map +1 -0
  168. package/dist/utils/format.d.ts +2 -0
  169. package/dist/utils/format.js +7 -13
  170. package/dist/utils/format.js.map +1 -1
  171. package/dist/utils/junit.d.ts +13 -0
  172. package/dist/utils/junit.js +81 -0
  173. package/dist/utils/junit.js.map +1 -0
  174. package/dist/utils/markdown.js +9 -4
  175. package/dist/utils/markdown.js.map +1 -1
  176. package/dist/utils/meeting.d.ts +13 -0
  177. package/dist/utils/meeting.js +118 -0
  178. package/dist/utils/meeting.js.map +1 -0
  179. package/dist/utils/people.d.ts +25 -0
  180. package/dist/utils/people.js +80 -0
  181. package/dist/utils/people.js.map +1 -0
  182. package/dist/utils/redact.d.ts +3 -0
  183. package/dist/utils/redact.js +26 -0
  184. package/dist/utils/redact.js.map +1 -0
  185. package/dist/utils/resolve.d.ts +17 -0
  186. package/dist/utils/resolve.js +54 -0
  187. package/dist/utils/resolve.js.map +1 -0
  188. package/dist/utils/spec.d.ts +10 -0
  189. package/dist/utils/spec.js +90 -0
  190. package/dist/utils/spec.js.map +1 -0
  191. package/dist/utils/storage.js +7 -3
  192. package/dist/utils/storage.js.map +1 -1
  193. package/dist/utils/tasks.d.ts +22 -0
  194. package/dist/utils/tasks.js +81 -0
  195. package/dist/utils/tasks.js.map +1 -0
  196. package/dist/watch.d.ts +62 -0
  197. package/dist/watch.js +405 -0
  198. package/dist/watch.js.map +1 -0
  199. package/package.json +4 -3
  200. package/scripts/setup.js +3 -1
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.removeContactChannel = exports.addContactChannel = exports.updatePerson = exports.createPerson = exports.getPerson = exports.listPersons = void 0;
7
+ const contact_1 = __importDefault(require("@hcengineering/contact"));
8
+ const core_1 = require("@hcengineering/core");
9
+ const connection_1 = require("../connection");
10
+ const errors_1 = require("../utils/errors");
11
+ const people_1 = require("../utils/people");
12
+ const provider = (name) => `contact:channelProvider:${name}`;
13
+ const providerName = (id) => String(id).split(':').pop() ?? id;
14
+ function splitName(raw) {
15
+ const [last, first] = (raw ?? '').split(',', 2);
16
+ return first === undefined ? { first: last.trim(), last: '' } : { first: first.trim(), last: last.trim() };
17
+ }
18
+ /** Any contact person (not only workspace users), by id or name. */
19
+ async function findAnyPerson(client, ref) {
20
+ const byId = await client.findOne(contact_1.default.class.Person, { _id: ref });
21
+ if (byId != null)
22
+ return byId;
23
+ const q = ref.trim().toLowerCase();
24
+ const persons = await client.findAll(contact_1.default.class.Person, {});
25
+ const exact = persons.filter((p) => (0, people_1.formatPersonName)(p.name).toLowerCase() === q || String(p.name ?? '').toLowerCase() === q);
26
+ if (exact.length === 1)
27
+ return exact[0];
28
+ const partial = persons.filter((p) => (0, people_1.formatPersonName)(p.name).toLowerCase().includes(q));
29
+ if (partial.length === 1)
30
+ return partial[0];
31
+ if (partial.length === 0)
32
+ throw new Error(`Person '${ref}' not found.`);
33
+ throw new Error(`Person '${ref}' is ambiguous: ${partial.map((p) => `${(0, people_1.formatPersonName)(p.name)} (\`${p._id}\`)`).join(', ')}.`);
34
+ }
35
+ function isEmployee(client, person) {
36
+ try {
37
+ return client.getHierarchy().hasMixin(person, contact_1.default.mixin.Employee);
38
+ }
39
+ catch {
40
+ return person[contact_1.default.mixin.Employee] != null;
41
+ }
42
+ }
43
+ exports.listPersons = (0, errors_1.wrapToolHandler)(async (args) => {
44
+ const client = await (0, connection_1.getConnection)(args.workspace);
45
+ let persons = await client.findAll(contact_1.default.class.Person, {});
46
+ if (args.employeesOnly)
47
+ persons = persons.filter((p) => isEmployee(client, p));
48
+ if (args.query != null)
49
+ persons = persons.filter((p) => (0, people_1.formatPersonName)(p.name).toLowerCase().includes(args.query.toLowerCase()));
50
+ persons.sort((a, b) => (0, people_1.formatPersonName)(a.name).localeCompare((0, people_1.formatPersonName)(b.name)));
51
+ const total = persons.length;
52
+ persons = persons.slice(0, args.limit);
53
+ if (persons.length === 0)
54
+ return 'No persons found.';
55
+ const channels = await client.findAll(contact_1.default.class.Channel, { attachedTo: { $in: persons.map((p) => p._id) } });
56
+ const lines = persons.map((p) => {
57
+ const ch = channels.filter((c) => c.attachedTo === p._id).map((c) => `${providerName(c.provider)}: ${c.value}`);
58
+ return `- **${(0, people_1.formatPersonName)(p.name)}**${isEmployee(client, p) ? ' (member)' : ''}${p.city != null && p.city !== '' ? ` · ${p.city}` : ''}${ch.length > 0 ? ` · ${ch.join(', ')}` : ''} — \`${p._id}\``;
59
+ });
60
+ return `## Persons (${total})\n\n${lines.join('\n')}${total > persons.length ? `\n\n_${total - persons.length} more (raise limit)._` : ''}`;
61
+ });
62
+ exports.getPerson = (0, errors_1.wrapToolHandler)(async (args) => {
63
+ const client = await (0, connection_1.getConnection)(args.workspace);
64
+ const p = await findAnyPerson(client, args.person);
65
+ const channels = await client.findAll(contact_1.default.class.Channel, { attachedTo: p._id });
66
+ const memberships = await client.findAll(contact_1.default.class.Member, { contact: p._id });
67
+ const orgs = [];
68
+ for (const m of memberships) {
69
+ const org = await client.findOne(contact_1.default.class.Organization, { _id: m.attachedTo });
70
+ if (org != null)
71
+ orgs.push(org.name);
72
+ }
73
+ return [
74
+ `## ${(0, people_1.formatPersonName)(p.name)}`,
75
+ `**Id:** \`${p._id}\``,
76
+ `**Workspace member:** ${isEmployee(client, p) ? 'yes' : 'no'}`,
77
+ p.city != null && p.city !== '' ? `**City:** ${p.city}` : null,
78
+ `**Contact channels:** ${channels.length > 0 ? channels.map((c) => `${providerName(c.provider)}: ${c.value}`).join(', ') : 'none'}`,
79
+ `**Organizations:** ${orgs.length > 0 ? orgs.join(', ') : 'none'}`
80
+ ].filter(Boolean).join('\n');
81
+ });
82
+ exports.createPerson = (0, errors_1.wrapToolHandler)(async (args) => {
83
+ const client = await (0, connection_1.getConnection)(args.workspace);
84
+ const name = `${args.lastName},${args.firstName}`;
85
+ const display = (0, people_1.formatPersonName)(name);
86
+ const existing = (await client.findAll(contact_1.default.class.Person, {})).filter((p) => (0, people_1.formatPersonName)(p.name).toLowerCase() === display.toLowerCase());
87
+ if (existing.length > 0)
88
+ return `ℹ️ **${display}** already exists (id: \`${existing[0]._id}\`).`;
89
+ const id = (0, core_1.generateId)();
90
+ // Huly stores names as "Last,First" (contact combineName).
91
+ await client.createDoc(contact_1.default.class.Person, contact_1.default.space.Contacts, { name, city: args.city ?? '', avatarType: 'color' }, id);
92
+ for (const ch of args.channels ?? []) {
93
+ await client.addCollection(contact_1.default.class.Channel, contact_1.default.space.Contacts, id, contact_1.default.class.Person, 'channels', { provider: provider(ch.provider), value: ch.value });
94
+ }
95
+ return `✅ Person **${display}** created (id: \`${id}\`)${(args.channels ?? []).length > 0 ? ` with ${args.channels.length} contact channel(s)` : ''}.`;
96
+ });
97
+ exports.updatePerson = (0, errors_1.wrapToolHandler)(async (args) => {
98
+ const client = await (0, connection_1.getConnection)(args.workspace);
99
+ const p = await findAnyPerson(client, args.person);
100
+ const updates = {};
101
+ if (args.firstName !== undefined || args.lastName !== undefined) {
102
+ const cur = splitName(p.name);
103
+ updates.name = `${args.lastName ?? cur.last},${args.firstName ?? cur.first}`;
104
+ }
105
+ if (args.city !== undefined)
106
+ updates.city = args.city;
107
+ if (Object.keys(updates).length === 0)
108
+ return `Nothing to update for **${(0, people_1.formatPersonName)(p.name)}**.`;
109
+ await client.updateDoc(contact_1.default.class.Person, p.space, p._id, updates);
110
+ return `✅ **${(0, people_1.formatPersonName)(updates.name ?? p.name)}** updated (${Object.keys(updates).join(', ')}).`;
111
+ });
112
+ exports.addContactChannel = (0, errors_1.wrapToolHandler)(async (args) => {
113
+ const client = await (0, connection_1.getConnection)(args.workspace);
114
+ const p = await findAnyPerson(client, args.person);
115
+ const existing = await client.findOne(contact_1.default.class.Channel, { attachedTo: p._id, provider: provider(args.provider), value: args.value });
116
+ if (existing != null)
117
+ return `ℹ️ ${(0, people_1.formatPersonName)(p.name)} already has ${args.provider}: ${args.value}.`;
118
+ await client.addCollection(contact_1.default.class.Channel, p.space, p._id, p._class, 'channels', { provider: provider(args.provider), value: args.value });
119
+ return `✅ Added ${args.provider} **${args.value}** to ${(0, people_1.formatPersonName)(p.name)}.`;
120
+ });
121
+ exports.removeContactChannel = (0, errors_1.wrapToolHandler)(async (args) => {
122
+ const client = await (0, connection_1.getConnection)(args.workspace);
123
+ const p = await findAnyPerson(client, args.person);
124
+ const ch = await client.findOne(contact_1.default.class.Channel, { attachedTo: p._id, provider: provider(args.provider), value: args.value });
125
+ if (ch == null)
126
+ return `${(0, people_1.formatPersonName)(p.name)} has no ${args.provider} "${args.value}".`;
127
+ await client.removeCollection(contact_1.default.class.Channel, ch.space, ch._id, p._id, ch.attachedToClass, 'channels');
128
+ return `✅ Removed ${args.provider} **${args.value}** from ${(0, people_1.formatPersonName)(p.name)}.`;
129
+ });
130
+ //# sourceMappingURL=contacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../src/tools/contacts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export declare const L: {
2
+ readonly Funnel: 'lead:class:Funnel';
3
+ readonly Lead: 'lead:class:Lead';
4
+ readonly Customer: 'lead:mixin:Customer';
5
+ readonly DefaultFunnel: 'lead:space:DefaultFunnel';
6
+ readonly Contacts: 'contact:space:Contacts';
7
+ };
8
+ export declare const listLeads: (args: {
9
+ workspace?: string | undefined;
10
+ funnel?: string | undefined;
11
+ status?: string | undefined;
12
+ limit?: number | undefined;
13
+ }) => Promise<{
14
+ content: Array<{
15
+ type: 'text';
16
+ text: string;
17
+ }>;
18
+ }>;
19
+ export declare const listCustomers: (args: {
20
+ workspace?: string | undefined;
21
+ }) => Promise<{
22
+ content: Array<{
23
+ type: 'text';
24
+ text: string;
25
+ }>;
26
+ }>;
27
+ export declare const createLead: (args: {
28
+ workspace: string;
29
+ title: string;
30
+ customer: string;
31
+ newCustomer?: "organization" | "person" | undefined;
32
+ funnel?: string | undefined;
33
+ status?: string | undefined;
34
+ assignee?: string | undefined;
35
+ }) => Promise<{
36
+ content: Array<{
37
+ type: 'text';
38
+ text: string;
39
+ }>;
40
+ }>;
41
+ export declare const updateLead: (args: {
42
+ workspace: string;
43
+ identifier: string;
44
+ title?: string | undefined;
45
+ status?: string | undefined;
46
+ assignee?: string | null | undefined;
47
+ }) => Promise<{
48
+ content: Array<{
49
+ type: 'text';
50
+ text: string;
51
+ }>;
52
+ }>;
53
+ export declare const deleteLead: (args: {
54
+ workspace: string;
55
+ identifier: string;
56
+ }) => Promise<{
57
+ content: Array<{
58
+ type: 'text';
59
+ text: string;
60
+ }>;
61
+ }>;
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteLead = exports.updateLead = exports.createLead = exports.listCustomers = exports.listLeads = exports.L = void 0;
4
+ // CRM (lead plugin): funnels (spaces), customers (Customer mixin on a person or organization)
5
+ // and leads (tasks LEAD-n attached to the customer, living in a funnel).
6
+ const core_1 = require("@hcengineering/core");
7
+ const connection_1 = require("../connection");
8
+ const errors_1 = require("../utils/errors");
9
+ const format_1 = require("../utils/format");
10
+ const people_1 = require("../utils/people");
11
+ const tasks_1 = require("../utils/tasks");
12
+ exports.L = {
13
+ Funnel: 'lead:class:Funnel',
14
+ Lead: 'lead:class:Lead',
15
+ Customer: 'lead:mixin:Customer',
16
+ DefaultFunnel: 'lead:space:DefaultFunnel',
17
+ Contacts: 'contact:space:Contacts'
18
+ };
19
+ async function findFunnel(client, ref) {
20
+ if (ref != null)
21
+ return await (0, tasks_1.findNamed)(client, exports.L.Funnel, ref, 'Funnel');
22
+ const funnels = await client.findAll(exports.L.Funnel, { archived: false });
23
+ if (funnels.length === 0)
24
+ throw new Error('No funnel in this workspace — is the CRM module enabled?');
25
+ return funnels.find((f) => f._id === exports.L.DefaultFunnel) ?? funnels[0];
26
+ }
27
+ async function findLead(client, identifier) {
28
+ const lead = await client.findOne(exports.L.Lead, { identifier: identifier.trim().toUpperCase() });
29
+ if (lead == null)
30
+ throw new Error(`Lead '${identifier}' not found (ids look like LEAD-12).`);
31
+ return lead;
32
+ }
33
+ exports.listLeads = (0, errors_1.wrapToolHandler)(async (args) => {
34
+ const client = await (0, connection_1.getConnection)(args.workspace);
35
+ const funnels = args.funnel != null ? [await findFunnel(client, args.funnel)] : await client.findAll(exports.L.Funnel, {});
36
+ const leads = await client.findAll(exports.L.Lead, { space: { $in: funnels.map((f) => f._id) } }, { sort: { modifiedOn: core_1.SortingOrder.Descending }, limit: args.limit ?? 50 });
37
+ const head = `## Leads (${leads.length}) — funnel(s): ${funnels.map((f) => f.name).join(', ') || 'none'}`;
38
+ if (leads.length === 0)
39
+ return `${head}\n\nNo leads.`;
40
+ const names = await (0, people_1.peopleNames)(client);
41
+ const customers = await client.findAll('contact:class:Contact', { _id: { $in: [...new Set(leads.map((l) => l.attachedTo))] } });
42
+ const wfs = new Map();
43
+ for (const f of funnels)
44
+ wfs.set(f._id, await (0, tasks_1.workflowOf)(client, f).catch(() => undefined));
45
+ const rows = leads.map((l) => ({ l, status: wfs.get(l.space) != null ? (0, tasks_1.statusName)(wfs.get(l.space), l.status) : '?' }))
46
+ .filter((r) => args.status == null || r.status.toLowerCase() === args.status.toLowerCase());
47
+ const lines = rows.map(({ l, status }) => `- **${String(l.identifier)}** ${String(l.title)} — ${(0, tasks_1.contactName)(customers.find((c) => c._id === l.attachedTo))} [${status}]${l.assignee != null ? ` · ${names.get(l.assignee) ?? '?'}` : ''} · ${(0, format_1.formatDate)(l.modifiedOn)}`);
48
+ return `${head}\n\n${lines.join('\n') || '_(none with that status)_'}`;
49
+ });
50
+ exports.listCustomers = (0, errors_1.wrapToolHandler)(async (args) => {
51
+ const client = await (0, connection_1.getConnection)(args.workspace);
52
+ const customers = await client.findAll(exports.L.Customer, {});
53
+ if (customers.length === 0)
54
+ return 'No customers.';
55
+ const lines = customers.map((c) => `- **${(0, tasks_1.contactName)(c)}** (${c._class === 'contact:class:Organization' ? 'organization' : 'person'}) · ${Number(c[exports.L.Customer]?.leads ?? 0)} lead(s) — \`${String(c._id)}\``);
56
+ return `## Customers (${customers.length})\n\n${lines.join('\n')}`;
57
+ });
58
+ exports.createLead = (0, errors_1.wrapToolHandler)(async (args) => {
59
+ const client = await (0, connection_1.getConnection)(args.workspace);
60
+ const funnel = await findFunnel(client, args.funnel);
61
+ const wf = await (0, tasks_1.workflowOf)(client, funnel);
62
+ const status = (0, tasks_1.pickStatus)(wf, args.status);
63
+ const assignee = args.assignee != null ? (await (0, people_1.findPerson)(client, args.assignee))._id : null;
64
+ let customer;
65
+ let created = '';
66
+ if (args.newCustomer != null) {
67
+ const cls = args.newCustomer === 'organization' ? 'contact:class:Organization' : 'contact:class:Person';
68
+ const name = args.newCustomer === 'organization' ? args.customer.trim() : (() => { const [first, ...rest] = args.customer.trim().split(/\s+/); return `${rest.join(' ')},${first}`; })();
69
+ const dup = await client.findAll(cls, { name });
70
+ if (dup.length > 0)
71
+ throw new Error(`'${args.customer}' already exists — leave out newCustomer to use it.`);
72
+ const id = (0, core_1.generateId)();
73
+ await client.createDoc(cls, exports.L.Contacts, { name, city: '', avatarType: 'color', ...(cls === 'contact:class:Organization' ? { description: null } : {}) }, id);
74
+ customer = { _id: id, _class: cls, space: exports.L.Contacts, name };
75
+ created = ` (new ${args.newCustomer})`;
76
+ }
77
+ else
78
+ customer = await (0, tasks_1.findContact)(client, args.customer);
79
+ if (customer[exports.L.Customer] == null)
80
+ await client.createMixin(customer._id, customer._class, customer.space, exports.L.Customer, { customerDescription: null });
81
+ const number = await (0, tasks_1.nextNumber)(client, exports.L.Lead);
82
+ const identifier = `LEAD-${number}`;
83
+ await client.addCollection(exports.L.Lead, funnel._id, customer._id, exports.L.Customer, 'leads', {
84
+ status, number, identifier, title: args.title.trim(), kind: wf.kind, rank: '', assignee, startDate: null, dueDate: null
85
+ });
86
+ return `✅ **${identifier}** ${args.title} — ${(0, tasks_1.contactName)(customer)}${created} [${(0, tasks_1.statusName)(wf, status)}] in ${String(funnel.name)}`;
87
+ });
88
+ exports.updateLead = (0, errors_1.wrapToolHandler)(async (args) => {
89
+ const client = await (0, connection_1.getConnection)(args.workspace);
90
+ const lead = await findLead(client, args.identifier);
91
+ const update = {};
92
+ const done = [];
93
+ if (args.title != null) {
94
+ update.title = args.title.trim();
95
+ done.push('title');
96
+ }
97
+ if (args.status != null) {
98
+ const wf = await (0, tasks_1.workflowOf)(client, await client.findOne(exports.L.Funnel, { _id: lead.space }));
99
+ update.status = (0, tasks_1.pickStatus)(wf, args.status);
100
+ done.push(`status → ${(0, tasks_1.statusName)(wf, update.status)}`);
101
+ }
102
+ if (args.assignee !== undefined) {
103
+ update.assignee = args.assignee != null ? (await (0, people_1.findPerson)(client, args.assignee))._id : null;
104
+ done.push(args.assignee != null ? `assignee → ${args.assignee}` : 'unassigned');
105
+ }
106
+ if (Object.keys(update).length === 0)
107
+ throw new Error('Nothing to change.');
108
+ await client.updateDoc(exports.L.Lead, lead.space, lead._id, update);
109
+ return `✅ **${String(lead.identifier)}**: ${done.join(', ')}.`;
110
+ });
111
+ exports.deleteLead = (0, errors_1.wrapToolHandler)(async (args) => {
112
+ const client = await (0, connection_1.getConnection)(args.workspace);
113
+ const lead = await findLead(client, args.identifier);
114
+ await client.removeCollection(exports.L.Lead, lead.space, lead._id, lead.attachedTo, lead.attachedToClass, lead.collection ?? 'leads');
115
+ return `🗑️ Lead **${String(lead.identifier)}** deleted.`;
116
+ });
117
+ //# sourceMappingURL=crm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crm.js","sourceRoot":"","sources":["../../src/tools/crm.ts"],"names":[],"mappings":"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"}
@@ -2,36 +2,36 @@ export declare const listTeamspaces: (args: {
2
2
  workspace?: string | undefined;
3
3
  }) => Promise<{
4
4
  content: Array<{
5
- type: "text";
5
+ type: 'text';
6
6
  text: string;
7
7
  }>;
8
8
  }>;
9
9
  export declare const createTeamspace: (args: {
10
10
  workspace: string;
11
11
  name: string;
12
- isPrivate: boolean;
13
12
  description?: string | undefined;
13
+ isPrivate: boolean;
14
14
  }) => Promise<{
15
15
  content: Array<{
16
- type: "text";
16
+ type: 'text';
17
17
  text: string;
18
18
  }>;
19
19
  }>;
20
20
  export declare const listDocuments: (args: {
21
- teamspaceId: string;
22
21
  workspace?: string | undefined;
22
+ teamspaceId: string;
23
23
  }) => Promise<{
24
24
  content: Array<{
25
- type: "text";
25
+ type: 'text';
26
26
  text: string;
27
27
  }>;
28
28
  }>;
29
29
  export declare const getDocument: (args: {
30
- documentId: string;
31
30
  workspace?: string | undefined;
31
+ documentId: string;
32
32
  }) => Promise<{
33
33
  content: Array<{
34
- type: "text";
34
+ type: 'text';
35
35
  text: string;
36
36
  }>;
37
37
  }>;
@@ -42,7 +42,7 @@ export declare const createDocument: (args: {
42
42
  parentId?: string | undefined;
43
43
  }) => Promise<{
44
44
  content: Array<{
45
- type: "text";
45
+ type: 'text';
46
46
  text: string;
47
47
  }>;
48
48
  }>;
@@ -51,17 +51,40 @@ export declare const deleteDocument: (args: {
51
51
  documentId: string;
52
52
  }) => Promise<{
53
53
  content: Array<{
54
- type: "text";
54
+ type: 'text';
55
55
  text: string;
56
56
  }>;
57
57
  }>;
58
58
  export declare const updateDocument: (args: {
59
59
  workspace: string;
60
60
  documentId: string;
61
- markdown: string;
61
+ markdown?: string | undefined;
62
+ title?: string | undefined;
63
+ parentId?: string | null | undefined;
64
+ teamspaceId?: string | undefined;
65
+ }) => Promise<{
66
+ content: Array<{
67
+ type: 'text';
68
+ text: string;
69
+ }>;
70
+ }>;
71
+ export declare const listDocumentComments: (args: {
72
+ workspace?: string | undefined;
73
+ documentId: string;
74
+ limit: number;
75
+ }) => Promise<{
76
+ content: Array<{
77
+ type: 'text';
78
+ text: string;
79
+ }>;
80
+ }>;
81
+ export declare const addDocumentComment: (args: {
82
+ workspace: string;
83
+ documentId: string;
84
+ message: string;
62
85
  }) => Promise<{
63
86
  content: Array<{
64
- type: "text";
87
+ type: 'text';
65
88
  text: string;
66
89
  }>;
67
90
  }>;
@@ -71,7 +94,7 @@ export declare const linkDocument: (args: {
71
94
  documentId: string;
72
95
  }) => Promise<{
73
96
  content: Array<{
74
- type: "text";
97
+ type: 'text';
75
98
  text: string;
76
99
  }>;
77
100
  }>;
@@ -36,15 +36,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.linkDocument = exports.updateDocument = exports.deleteDocument = exports.createDocument = exports.getDocument = exports.listDocuments = exports.createTeamspace = exports.listTeamspaces = void 0;
39
+ exports.linkDocument = exports.addDocumentComment = exports.listDocumentComments = exports.updateDocument = exports.deleteDocument = exports.createDocument = exports.getDocument = exports.listDocuments = exports.createTeamspace = exports.listTeamspaces = void 0;
40
40
  const document_1 = __importDefault(require("@hcengineering/document"));
41
41
  const core_1 = __importStar(require("@hcengineering/core"));
42
42
  const document_2 = require("@hcengineering/document");
43
+ const rank_1 = require("@hcengineering/rank");
44
+ const chunter_1 = __importDefault(require("@hcengineering/chunter"));
45
+ const people_1 = require("../utils/people");
46
+ const format_1 = require("../utils/format");
43
47
  const connection_1 = require("../connection");
44
48
  const errors_1 = require("../utils/errors");
45
49
  const markdown_1 = require("../utils/markdown");
46
50
  const storage_1 = require("../utils/storage");
47
51
  const tracker_1 = __importDefault(require("@hcengineering/tracker"));
52
+ const content_1 = require("../utils/content");
48
53
  exports.listTeamspaces = (0, errors_1.wrapToolHandler)(async (args) => {
49
54
  const client = await (0, connection_1.getConnection)(args.workspace);
50
55
  const teamspaces = await client.findAll(document_1.default.class.Teamspace, {});
@@ -56,12 +61,14 @@ exports.listTeamspaces = (0, errors_1.wrapToolHandler)(async (args) => {
56
61
  exports.createTeamspace = (0, errors_1.wrapToolHandler)(async (args) => {
57
62
  const client = await (0, connection_1.getConnection)(args.workspace);
58
63
  const teamspaceId = (0, core_1.generateId)();
64
+ // Space members and owners are account uuids in Huly 0.7 (not the social id in client.user).
65
+ const me = await (0, people_1.currentAccountUuid)(client);
59
66
  await client.createDoc(document_1.default.class.Teamspace, core_1.default.space.Space, {
60
67
  name: args.name,
61
68
  description: args.description ?? '',
62
69
  private: args.isPrivate ?? false,
63
- members: [client.user],
64
- owners: [client.user],
70
+ members: [me],
71
+ owners: [me],
65
72
  autoJoin: false,
66
73
  archived: false,
67
74
  icon: undefined,
@@ -75,13 +82,23 @@ exports.listDocuments = (0, errors_1.wrapToolHandler)(async (args) => {
75
82
  const docs = await client.findAll(document_1.default.class.Document, { space: args.teamspaceId }, { sort: { rank: core_1.SortingOrder.Ascending }, limit: 100 });
76
83
  if (docs.length === 0)
77
84
  return 'No documents found in this teamspace.';
78
- // Build parent-child tree display
85
+ // Real tree: children under their parent, any depth.
79
86
  const noParentId = document_1.default.ids.NoParent;
80
- const lines = docs.map((d) => {
81
- const isNested = d.parent != null && String(d.parent) !== noParentId;
82
- const prefix = isNested ? ' - ' : '- ';
83
- return `${prefix}**${d.title}** (id: \`${d._id}\`)${d.snapshots != null && d.snapshots > 0 ? ` [${d.snapshots} snapshots]` : ''}`;
84
- });
87
+ const ids = new Set(docs.map((d) => String(d._id)));
88
+ const byParent = new Map();
89
+ for (const d of docs) {
90
+ const p = d.parent != null && String(d.parent) !== noParentId && ids.has(String(d.parent)) ? String(d.parent) : noParentId;
91
+ byParent.set(p, [...(byParent.get(p) ?? []), d]);
92
+ }
93
+ const lines = [];
94
+ const walk = (parent, depth) => {
95
+ for (const d of byParent.get(parent) ?? []) {
96
+ lines.push(`${' '.repeat(depth)}- **${d.title}** (id: \`${d._id}\`)${d.comments > 0 ? ` · ${d.comments} comment(s)` : ''}`);
97
+ if (depth < 20)
98
+ walk(String(d._id), depth + 1);
99
+ }
100
+ };
101
+ walk(noParentId, 0);
85
102
  return `## Documents (${docs.length})\n\n${lines.join('\n')}`;
86
103
  });
87
104
  exports.getDocument = (0, errors_1.wrapToolHandler)(async (args) => {
@@ -110,7 +127,7 @@ exports.getDocument = (0, errors_1.wrapToolHandler)(async (args) => {
110
127
  lines.push(`**Content URL:** ${contentUrl} _(requires a workspace token as Bearer header)_`);
111
128
  // Try to fetch content
112
129
  try {
113
- const res = await fetch(contentUrl, { headers: { Authorization: `Bearer ${wsToken}` } });
130
+ const res = await (0, content_1.fetchBlob)(contentUrl, wsToken);
114
131
  if (res.ok) {
115
132
  const text = await res.text();
116
133
  // Huly stores content as JSON markup — extract plain text if possible
@@ -147,14 +164,14 @@ exports.createDocument = (0, errors_1.wrapToolHandler)(async (args) => {
147
164
  throw new Error(`Teamspace '${args.teamspaceId}' not found.`);
148
165
  const noParent = document_1.default.ids.NoParent;
149
166
  const parentId = args.parentId != null ? args.parentId : noParent;
150
- // Compute rank (prepend before existing docs at same level)
151
- const rank = await (0, document_2.getFirstRank)(client, teamspace._id, parentId);
167
+ // Like Huly: after the last sibling.
168
+ const rank = (0, rank_1.makeRank)(await (0, document_2.getFirstRank)(client, teamspace._id, parentId), undefined);
152
169
  const docId = (0, core_1.generateId)();
153
170
  await client.createDoc(document_1.default.class.Document, teamspace._id, {
154
171
  title: args.title,
155
172
  content: null,
156
173
  parent: parentId,
157
- rank: rank ?? '',
174
+ rank,
158
175
  icon: null,
159
176
  color: undefined,
160
177
  snapshots: 0,
@@ -174,20 +191,88 @@ exports.deleteDocument = (0, errors_1.wrapToolHandler)(async (args) => {
174
191
  await client.removeDoc(document_1.default.class.Document, doc.space, doc._id);
175
192
  return `✅ Document **"${doc.title}"** (\`${doc._id}\`) deleted.`;
176
193
  });
194
+ /** All descendants of a document (any depth). */
195
+ async function descendants(client, root) {
196
+ const out = [];
197
+ let level = [root._id];
198
+ while (level.length > 0) {
199
+ const kids = await client.findAll(document_1.default.class.Document, { parent: { $in: level } });
200
+ out.push(...kids);
201
+ level = kids.map((k) => k._id);
202
+ }
203
+ return out;
204
+ }
177
205
  exports.updateDocument = (0, errors_1.wrapToolHandler)(async (args) => {
178
206
  const client = await (0, connection_1.getConnection)(args.workspace);
179
- const { wsToken, workspaceUuid } = await (0, connection_1.getWorkspaceInfo)(args.workspace);
180
207
  const doc = await client.findOne(document_1.default.class.Document, { _id: args.documentId });
181
208
  if (doc == null)
182
209
  throw new Error(`Document '${args.documentId}' not found.`);
183
- // Convert markdown to ProseMirror JSON
184
- const prosemirror = (0, markdown_1.markdownToProseMirror)(args.markdown);
185
- const content = JSON.stringify(prosemirror);
186
- const blobId = `${args.documentId}-content-${Date.now()}`;
187
- const uploadedId = await (0, storage_1.uploadMarkupBlob)(wsToken, workspaceUuid, blobId, content);
188
- // Update document content ref
189
- await client.updateDoc(document_1.default.class.Document, doc.space, doc._id, { content: uploadedId });
190
- return `✅ Document **"${doc.title}"** updated (blob: \`${uploadedId}\`).`;
210
+ if (args.markdown == null && args.title == null && args.parentId === undefined && args.teamspaceId == null) {
211
+ throw new Error('Nothing to change: pass markdown, title, parentId or teamspaceId.');
212
+ }
213
+ const done = [];
214
+ // Move (new parent and/or teamspace) — validated before anything is written.
215
+ const moving = args.parentId !== undefined || args.teamspaceId != null;
216
+ let move;
217
+ let subtree = [];
218
+ if (moving) {
219
+ const noParent = document_1.default.ids.NoParent;
220
+ let parent;
221
+ if (args.parentId != null) {
222
+ parent = await client.findOne(document_1.default.class.Document, { _id: args.parentId });
223
+ if (parent == null)
224
+ throw new Error(`Parent document '${args.parentId}' not found.`);
225
+ }
226
+ const space = parent?.space ?? args.teamspaceId ?? doc.space;
227
+ if (args.teamspaceId != null && parent != null && parent.space !== args.teamspaceId)
228
+ throw new Error('parentId is in a different teamspace than teamspaceId.');
229
+ if (space !== doc.space && (await client.findOne(document_1.default.class.Teamspace, { _id: space })) == null)
230
+ throw new Error(`Teamspace '${String(space)}' not found.`);
231
+ subtree = await descendants(client, doc);
232
+ if (parent != null && (parent._id === doc._id || subtree.some((d) => d._id === parent._id)))
233
+ throw new Error('A document cannot be moved under itself or one of its children.');
234
+ const parentId = parent?._id ?? (args.parentId === null || args.teamspaceId != null ? noParent : doc.parent);
235
+ move = { space, parent: parentId, rank: (0, rank_1.makeRank)(await (0, document_2.getFirstRank)(client, space, parentId), undefined) };
236
+ }
237
+ if (args.markdown != null) {
238
+ const { wsToken, workspaceUuid } = await (0, connection_1.getWorkspaceInfo)(args.workspace);
239
+ const uploadedId = await (0, storage_1.uploadMarkupBlob)(wsToken, workspaceUuid, `${args.documentId}-content-${Date.now()}`, JSON.stringify((0, markdown_1.markdownToProseMirror)(args.markdown)));
240
+ await client.updateDoc(document_1.default.class.Document, doc.space, doc._id, { content: uploadedId });
241
+ done.push('content replaced');
242
+ }
243
+ if (args.title != null && args.title !== doc.title) {
244
+ await client.updateDoc(document_1.default.class.Document, doc.space, doc._id, { title: args.title });
245
+ done.push(`renamed to "${args.title}"`);
246
+ }
247
+ if (move != null) {
248
+ await client.updateDoc(document_1.default.class.Document, doc.space, doc._id, move);
249
+ // Children keep their parent but must live in the same teamspace.
250
+ if (move.space !== doc.space)
251
+ for (const d of subtree)
252
+ await client.updateDoc(document_1.default.class.Document, d.space, d._id, { space: move.space });
253
+ done.push(`moved${move.space !== doc.space ? ` to another teamspace (with ${subtree.length} sub-document(s))` : ''}${String(move.parent) === document_1.default.ids.NoParent ? ' to top level' : ' under the new parent'}`);
254
+ }
255
+ return `✅ Document **"${args.title ?? doc.title}"**: ${done.join(', ') || 'no change'}.`;
256
+ });
257
+ exports.listDocumentComments = (0, errors_1.wrapToolHandler)(async (args) => {
258
+ const client = await (0, connection_1.getConnection)(args.workspace);
259
+ const doc = await client.findOne(document_1.default.class.Document, { _id: args.documentId });
260
+ if (doc == null)
261
+ throw new Error(`Document '${args.documentId}' not found.`);
262
+ const comments = await client.findAll(chunter_1.default.class.ChatMessage, { attachedTo: doc._id }, { sort: { createdOn: core_1.SortingOrder.Ascending }, limit: args.limit });
263
+ if (comments.length === 0)
264
+ return `No comments on "${doc.title}".`;
265
+ const names = await (0, people_1.socialIdNames)(client, [...new Set(comments.map((c) => c.createdBy).filter((x) => x != null))]);
266
+ const lines = comments.map((c) => `- **${names.get(c.createdBy) ?? 'Unknown'}** (${new Date(c.createdOn ?? 0).toISOString().slice(0, 16).replace('T', ' ')}) — \`${c._id}\`\n ${(0, format_1.markupToText)(c.message).replace(/\n/g, '\n ')}`);
267
+ return `## Comments on "${doc.title}" (${comments.length})\n\n${lines.join('\n')}`;
268
+ });
269
+ exports.addDocumentComment = (0, errors_1.wrapToolHandler)(async (args) => {
270
+ const client = await (0, connection_1.getConnection)(args.workspace);
271
+ const doc = await client.findOne(document_1.default.class.Document, { _id: args.documentId });
272
+ if (doc == null)
273
+ throw new Error(`Document '${args.documentId}' not found.`);
274
+ await client.addCollection(chunter_1.default.class.ChatMessage, doc.space, doc._id, document_1.default.class.Document, 'comments', { message: args.message });
275
+ return `✅ Comment added to "${doc.title}".`;
191
276
  });
192
277
  exports.linkDocument = (0, errors_1.wrapToolHandler)(async (args) => {
193
278
  const client = await (0, connection_1.getConnection)(args.workspace);