@open-mercato/core 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2

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 (163) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +13 -1
  3. package/dist/helpers/integration/api.js +29 -16
  4. package/dist/helpers/integration/api.js.map +2 -2
  5. package/dist/helpers/integration/auth.js +11 -6
  6. package/dist/helpers/integration/auth.js.map +3 -3
  7. package/dist/modules/auth/commands/roles.js +9 -12
  8. package/dist/modules/auth/commands/roles.js.map +2 -2
  9. package/dist/modules/catalog/ai-agents-context.js +147 -0
  10. package/dist/modules/catalog/ai-agents-context.js.map +7 -0
  11. package/dist/modules/catalog/ai-agents.js +383 -0
  12. package/dist/modules/catalog/ai-agents.js.map +7 -0
  13. package/dist/modules/catalog/ai-tools/_shared.js +318 -0
  14. package/dist/modules/catalog/ai-tools/_shared.js.map +7 -0
  15. package/dist/modules/catalog/ai-tools/authoring-pack.js +391 -0
  16. package/dist/modules/catalog/ai-tools/authoring-pack.js.map +7 -0
  17. package/dist/modules/catalog/ai-tools/categories-pack.js +167 -0
  18. package/dist/modules/catalog/ai-tools/categories-pack.js.map +7 -0
  19. package/dist/modules/catalog/ai-tools/configuration-pack.js +120 -0
  20. package/dist/modules/catalog/ai-tools/configuration-pack.js.map +7 -0
  21. package/dist/modules/catalog/ai-tools/media-tags-pack.js +107 -0
  22. package/dist/modules/catalog/ai-tools/media-tags-pack.js.map +7 -0
  23. package/dist/modules/catalog/ai-tools/merchandising-pack.js +429 -0
  24. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +7 -0
  25. package/dist/modules/catalog/ai-tools/mutation-pack.js +576 -0
  26. package/dist/modules/catalog/ai-tools/mutation-pack.js.map +7 -0
  27. package/dist/modules/catalog/ai-tools/prices-offers-pack.js +208 -0
  28. package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +7 -0
  29. package/dist/modules/catalog/ai-tools/products-pack.js +298 -0
  30. package/dist/modules/catalog/ai-tools/products-pack.js.map +7 -0
  31. package/dist/modules/catalog/ai-tools/stats-pack.js +57 -0
  32. package/dist/modules/catalog/ai-tools/stats-pack.js.map +7 -0
  33. package/dist/modules/catalog/ai-tools/types.js +10 -0
  34. package/dist/modules/catalog/ai-tools/types.js.map +7 -0
  35. package/dist/modules/catalog/ai-tools/variants-pack.js +75 -0
  36. package/dist/modules/catalog/ai-tools/variants-pack.js.map +7 -0
  37. package/dist/modules/catalog/ai-tools.js +28 -0
  38. package/dist/modules/catalog/ai-tools.js.map +7 -0
  39. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +466 -0
  40. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +7 -0
  41. package/dist/modules/catalog/backend/catalog/products/page.js +7 -1
  42. package/dist/modules/catalog/backend/catalog/products/page.js.map +2 -2
  43. package/dist/modules/catalog/components/CatalogStatsCard.js +91 -0
  44. package/dist/modules/catalog/components/CatalogStatsCard.js.map +7 -0
  45. package/dist/modules/catalog/components/products/ProductsDataTable.js +23 -3
  46. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  47. package/dist/modules/catalog/events.js +7 -4
  48. package/dist/modules/catalog/events.js.map +2 -2
  49. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +59 -0
  50. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +7 -0
  51. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js +17 -0
  52. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js.map +7 -0
  53. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
  54. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
  55. package/dist/modules/catalog/widgets/injection-table.js +13 -1
  56. package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
  57. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +94 -0
  58. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +7 -0
  59. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js +17 -0
  60. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js.map +7 -0
  61. package/dist/modules/customer_accounts/widgets/injection-table.js +9 -0
  62. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  63. package/dist/modules/customers/ai-agents-context.js +96 -0
  64. package/dist/modules/customers/ai-agents-context.js.map +7 -0
  65. package/dist/modules/customers/ai-agents.js +244 -0
  66. package/dist/modules/customers/ai-agents.js.map +7 -0
  67. package/dist/modules/customers/ai-tools/activities-tasks-pack.js +1015 -0
  68. package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +7 -0
  69. package/dist/modules/customers/ai-tools/addresses-tags-pack.js +134 -0
  70. package/dist/modules/customers/ai-tools/addresses-tags-pack.js.map +7 -0
  71. package/dist/modules/customers/ai-tools/companies-pack.js +249 -0
  72. package/dist/modules/customers/ai-tools/companies-pack.js.map +7 -0
  73. package/dist/modules/customers/ai-tools/deals-pack.js +348 -0
  74. package/dist/modules/customers/ai-tools/deals-pack.js.map +7 -0
  75. package/dist/modules/customers/ai-tools/people-pack.js +261 -0
  76. package/dist/modules/customers/ai-tools/people-pack.js.map +7 -0
  77. package/dist/modules/customers/ai-tools/settings-pack.js +102 -0
  78. package/dist/modules/customers/ai-tools/settings-pack.js.map +7 -0
  79. package/dist/modules/customers/ai-tools/types.js +10 -0
  80. package/dist/modules/customers/ai-tools/types.js.map +7 -0
  81. package/dist/modules/customers/ai-tools.js +20 -0
  82. package/dist/modules/customers/ai-tools.js.map +7 -0
  83. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +469 -0
  84. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +7 -0
  85. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +17 -0
  86. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +7 -0
  87. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +117 -0
  88. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +7 -0
  89. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js +17 -0
  90. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js.map +7 -0
  91. package/dist/modules/customers/widgets/injection-table.js +26 -0
  92. package/dist/modules/customers/widgets/injection-table.js.map +7 -0
  93. package/dist/modules/inbox_ops/ai-tools.js +4 -0
  94. package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
  95. package/dist/modules/inbox_ops/lib/llmProvider.js +52 -7
  96. package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
  97. package/dist/modules/notifications/setup.js +13 -0
  98. package/dist/modules/notifications/setup.js.map +7 -0
  99. package/jest.config.cjs +1 -0
  100. package/jest.setup.ts +18 -0
  101. package/package.json +5 -3
  102. package/src/helpers/integration/api.ts +38 -16
  103. package/src/helpers/integration/auth.ts +13 -6
  104. package/src/modules/auth/commands/roles.ts +10 -12
  105. package/src/modules/catalog/AGENTS.md +11 -0
  106. package/src/modules/catalog/ai-agents-context.ts +239 -0
  107. package/src/modules/catalog/ai-agents.ts +525 -0
  108. package/src/modules/catalog/ai-tools/_shared.ts +487 -0
  109. package/src/modules/catalog/ai-tools/authoring-pack.ts +600 -0
  110. package/src/modules/catalog/ai-tools/categories-pack.ts +192 -0
  111. package/src/modules/catalog/ai-tools/configuration-pack.ts +218 -0
  112. package/src/modules/catalog/ai-tools/media-tags-pack.ts +127 -0
  113. package/src/modules/catalog/ai-tools/merchandising-pack.ts +608 -0
  114. package/src/modules/catalog/ai-tools/mutation-pack.ts +761 -0
  115. package/src/modules/catalog/ai-tools/prices-offers-pack.ts +376 -0
  116. package/src/modules/catalog/ai-tools/products-pack.ts +387 -0
  117. package/src/modules/catalog/ai-tools/stats-pack.ts +84 -0
  118. package/src/modules/catalog/ai-tools/types.ts +81 -0
  119. package/src/modules/catalog/ai-tools/variants-pack.ts +147 -0
  120. package/src/modules/catalog/ai-tools.ts +78 -0
  121. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +597 -0
  122. package/src/modules/catalog/backend/catalog/products/page.tsx +23 -2
  123. package/src/modules/catalog/components/CatalogStatsCard.tsx +118 -0
  124. package/src/modules/catalog/components/products/ProductsDataTable.tsx +54 -6
  125. package/src/modules/catalog/events.ts +7 -4
  126. package/src/modules/catalog/i18n/de.json +17 -0
  127. package/src/modules/catalog/i18n/en.json +17 -0
  128. package/src/modules/catalog/i18n/es.json +17 -0
  129. package/src/modules/catalog/i18n/pl.json +17 -0
  130. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +109 -0
  131. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.ts +29 -0
  132. package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
  133. package/src/modules/catalog/widgets/injection-table.ts +12 -0
  134. package/src/modules/customer_accounts/i18n/de.json +5 -0
  135. package/src/modules/customer_accounts/i18n/en.json +5 -0
  136. package/src/modules/customer_accounts/i18n/es.json +5 -0
  137. package/src/modules/customer_accounts/i18n/pl.json +5 -0
  138. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +136 -0
  139. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.ts +43 -0
  140. package/src/modules/customer_accounts/widgets/injection-table.ts +9 -0
  141. package/src/modules/customers/AGENTS.md +13 -0
  142. package/src/modules/customers/ai-agents-context.ts +150 -0
  143. package/src/modules/customers/ai-agents.ts +355 -0
  144. package/src/modules/customers/ai-tools/activities-tasks-pack.ts +1248 -0
  145. package/src/modules/customers/ai-tools/addresses-tags-pack.ts +145 -0
  146. package/src/modules/customers/ai-tools/companies-pack.ts +362 -0
  147. package/src/modules/customers/ai-tools/deals-pack.ts +505 -0
  148. package/src/modules/customers/ai-tools/people-pack.ts +369 -0
  149. package/src/modules/customers/ai-tools/settings-pack.ts +121 -0
  150. package/src/modules/customers/ai-tools/types.ts +76 -0
  151. package/src/modules/customers/ai-tools.ts +34 -0
  152. package/src/modules/customers/i18n/de.json +25 -0
  153. package/src/modules/customers/i18n/en.json +25 -0
  154. package/src/modules/customers/i18n/es.json +25 -0
  155. package/src/modules/customers/i18n/pl.json +25 -0
  156. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +580 -0
  157. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +36 -0
  158. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +191 -0
  159. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.ts +37 -0
  160. package/src/modules/customers/widgets/injection-table.ts +41 -0
  161. package/src/modules/inbox_ops/ai-tools.ts +4 -0
  162. package/src/modules/inbox_ops/lib/llmProvider.ts +83 -7
  163. package/src/modules/notifications/setup.ts +11 -0
@@ -0,0 +1,261 @@
1
+ import { z } from "zod";
2
+ import { defineApiBackedAiTool } from "@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool";
3
+ import {
4
+ createAiApiOperationRunner
5
+ } from "@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner";
6
+ import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
7
+ import {
8
+ CustomerPersonProfile
9
+ } from "../data/entities.js";
10
+ import { assertTenantScope } from "./types.js";
11
+ const NIL_UUID = "00000000-0000-0000-0000-000000000000";
12
+ function resolveEm(ctx) {
13
+ return ctx.container.resolve("em");
14
+ }
15
+ function buildScope(ctx, tenantId) {
16
+ return {
17
+ tenantId,
18
+ organizationId: ctx.organizationId
19
+ };
20
+ }
21
+ const listPeopleInput = z.object({
22
+ q: z.string().trim().optional().describe("Optional search text matched against display name / email / phone. Omit or leave empty to list all."),
23
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum rows to return (default 50, max 100)."),
24
+ offset: z.number().int().min(0).optional().describe("Number of rows to skip (default 0)."),
25
+ tags: z.array(z.string().uuid()).optional().describe("Restrict to persons carrying at least one of these tag ids."),
26
+ companyId: z.string().uuid().optional().describe("Restrict to persons linked to the given company entity.")
27
+ }).passthrough();
28
+ const listPeopleTool = defineApiBackedAiTool({
29
+ name: "customers.list_people",
30
+ displayName: "List people",
31
+ description: "Search / list people (CRM persons) for the caller tenant + organization. Returns { items, total, limit, offset }.",
32
+ inputSchema: listPeopleInput,
33
+ requiredFeatures: ["customers.people.view"],
34
+ toOperation: async (input, ctx) => {
35
+ const { tenantId } = assertTenantScope(ctx);
36
+ const limit = input.limit ?? 50;
37
+ const offset = input.offset ?? 0;
38
+ const page = Math.floor(offset / limit) + 1;
39
+ const query = {
40
+ page,
41
+ pageSize: limit
42
+ };
43
+ if (input.q?.trim()) query.search = input.q.trim();
44
+ if (input.tags && input.tags.length > 0) query.tagIds = input.tags.join(",");
45
+ if (input.companyId) {
46
+ const em = resolveEm(ctx);
47
+ const profiles = await findWithDecryption(
48
+ em,
49
+ CustomerPersonProfile,
50
+ { tenantId, company: input.companyId },
51
+ void 0,
52
+ buildScope(ctx, tenantId)
53
+ );
54
+ const ids = profiles.map((profile) => {
55
+ const entity = profile.entity;
56
+ if (!entity) return null;
57
+ if (typeof entity === "string") return entity;
58
+ const candidate = entity.id;
59
+ return typeof candidate === "string" ? candidate : null;
60
+ }).filter((value) => typeof value === "string" && value.length > 0);
61
+ query.ids = ids.length ? ids.join(",") : NIL_UUID;
62
+ }
63
+ const operation = {
64
+ method: "GET",
65
+ path: "/customers/people",
66
+ query
67
+ };
68
+ return operation;
69
+ },
70
+ mapResponse: (response, input) => {
71
+ const limit = input.limit ?? 50;
72
+ const offset = input.offset ?? 0;
73
+ const data = response.data ?? {};
74
+ const rawItems = Array.isArray(data.items) ? data.items : [];
75
+ return {
76
+ items: rawItems.map((row) => {
77
+ const createdAtRaw = row.created_at ?? row.createdAt ?? null;
78
+ const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null;
79
+ return {
80
+ id: row.id,
81
+ displayName: row.display_name ?? row.displayName ?? null,
82
+ primaryEmail: row.primary_email ?? row.primaryEmail ?? null,
83
+ primaryPhone: row.primary_phone ?? row.primaryPhone ?? null,
84
+ status: row.status ?? null,
85
+ lifecycleStage: row.lifecycle_stage ?? row.lifecycleStage ?? null,
86
+ source: row.source ?? null,
87
+ ownerUserId: row.owner_user_id ?? row.ownerUserId ?? null,
88
+ organizationId: row.organization_id ?? row.organizationId ?? null,
89
+ tenantId: row.tenant_id ?? row.tenantId ?? null,
90
+ createdAt
91
+ };
92
+ }),
93
+ total: typeof data.total === "number" ? data.total : 0,
94
+ limit,
95
+ offset
96
+ };
97
+ }
98
+ });
99
+ const getPersonInput = z.object({
100
+ personId: z.string().uuid().describe("Person entity id (UUID)."),
101
+ includeRelated: z.boolean().optional().describe("When true, include notes, activities, deals, addresses, tasks, and tags (each capped at 100).")
102
+ });
103
+ function toIso(value) {
104
+ if (!value) return null;
105
+ const dt = value instanceof Date ? value : new Date(String(value));
106
+ if (Number.isNaN(dt.getTime())) return null;
107
+ return dt.toISOString();
108
+ }
109
+ const getPersonTool = {
110
+ name: "customers.get_person",
111
+ displayName: "Get person",
112
+ description: "Fetch a person customer record by id with profile fields and (optionally) notes, activities, deals, addresses, tasks, tags, and custom fields. Returns { found: false } when the record is outside tenant/org scope or missing.",
113
+ inputSchema: getPersonInput,
114
+ requiredFeatures: ["customers.people.view"],
115
+ tags: ["read", "customers"],
116
+ handler: async (rawInput, ctx) => {
117
+ const { tenantId } = assertTenantScope(ctx);
118
+ const input = getPersonInput.parse(rawInput);
119
+ const includeRelated = !!input.includeRelated;
120
+ const operation = {
121
+ method: "GET",
122
+ path: `/customers/people/${input.personId}`
123
+ };
124
+ if (includeRelated) {
125
+ operation.query = { include: "addresses,comments,activities,interactions,deals,todos" };
126
+ }
127
+ const runner = createAiApiOperationRunner(ctx);
128
+ const response = await runner.run(operation);
129
+ if (!response.success) {
130
+ if (response.statusCode === 404 || response.statusCode === 403) {
131
+ return { found: false, personId: input.personId };
132
+ }
133
+ throw new Error(response.error ?? `Failed to fetch person ${input.personId}`);
134
+ }
135
+ const data = response.data ?? {};
136
+ const personRow = data.person ?? null;
137
+ if (!personRow) {
138
+ return { found: false, personId: input.personId };
139
+ }
140
+ const profileRow = data.profile ?? null;
141
+ const customFields = data.customFields ?? {};
142
+ let related = null;
143
+ if (includeRelated) {
144
+ const addresses = Array.isArray(data.addresses) ? data.addresses : [];
145
+ const activities = Array.isArray(data.activities) ? data.activities : [];
146
+ const notes = Array.isArray(data.comments) ? data.comments : [];
147
+ const todos = Array.isArray(data.todos) ? data.todos : [];
148
+ const interactions = Array.isArray(data.interactions) ? data.interactions : [];
149
+ const tagsRows = Array.isArray(data.tags) ? data.tags : [];
150
+ const dealsRows = Array.isArray(data.deals) ? data.deals : [];
151
+ related = {
152
+ addresses: addresses.map((address) => ({
153
+ id: address.id,
154
+ name: address.name ?? null,
155
+ purpose: address.purpose ?? null,
156
+ addressLine1: address.addressLine1 ?? null,
157
+ addressLine2: address.addressLine2 ?? null,
158
+ city: address.city ?? null,
159
+ region: address.region ?? null,
160
+ postalCode: address.postalCode ?? null,
161
+ country: address.country ?? null,
162
+ isPrimary: !!address.isPrimary
163
+ })),
164
+ activities: activities.map((activity) => ({
165
+ id: activity.id,
166
+ activityType: activity.activityType,
167
+ subject: activity.subject ?? null,
168
+ body: activity.body ?? null,
169
+ occurredAt: toIso(activity.occurredAt),
170
+ createdAt: toIso(activity.createdAt)
171
+ })),
172
+ notes: notes.map((comment) => ({
173
+ id: comment.id,
174
+ body: comment.body,
175
+ authorUserId: comment.authorUserId ?? null,
176
+ createdAt: toIso(comment.createdAt)
177
+ })),
178
+ tasks: todos.map((task) => ({
179
+ id: task.id,
180
+ todoId: task.todoId ?? task.id,
181
+ todoSource: task.todoSource ?? null,
182
+ createdAt: toIso(task.createdAt)
183
+ })),
184
+ interactions: interactions.map((interaction) => ({
185
+ id: interaction.id,
186
+ interactionType: interaction.interactionType,
187
+ title: interaction.title ?? null,
188
+ status: interaction.status,
189
+ scheduledAt: toIso(interaction.scheduledAt),
190
+ occurredAt: toIso(interaction.occurredAt)
191
+ })),
192
+ tags: tagsRows.map((tag) => {
193
+ if (!tag || typeof tag !== "object") return null;
194
+ const id = typeof tag.id === "string" ? tag.id : null;
195
+ const label = typeof tag.label === "string" ? tag.label : null;
196
+ if (!id || !label) return null;
197
+ const slug = typeof tag.slug === "string" ? tag.slug : label;
198
+ const color = typeof tag.color === "string" ? tag.color : null;
199
+ return { id, slug, label, color };
200
+ }).filter(
201
+ (entry) => entry !== null
202
+ ),
203
+ deals: dealsRows.map((deal) => {
204
+ if (!deal || typeof deal !== "object") return null;
205
+ const id = typeof deal.id === "string" ? deal.id : null;
206
+ if (!id) return null;
207
+ return {
208
+ id,
209
+ title: typeof deal.title === "string" ? deal.title : "",
210
+ status: typeof deal.status === "string" ? deal.status : null,
211
+ pipelineStageId: typeof deal.pipelineStageId === "string" ? deal.pipelineStageId : null,
212
+ valueAmount: typeof deal.valueAmount === "string" ? deal.valueAmount : deal.valueAmount === null || deal.valueAmount === void 0 ? null : String(deal.valueAmount),
213
+ valueCurrency: typeof deal.valueCurrency === "string" ? deal.valueCurrency : null
214
+ };
215
+ }).filter(
216
+ (value) => value !== null
217
+ )
218
+ };
219
+ }
220
+ return {
221
+ found: true,
222
+ person: {
223
+ id: personRow.id,
224
+ displayName: personRow.displayName ?? null,
225
+ description: personRow.description ?? null,
226
+ primaryEmail: personRow.primaryEmail ?? null,
227
+ primaryPhone: personRow.primaryPhone ?? null,
228
+ status: personRow.status ?? null,
229
+ lifecycleStage: personRow.lifecycleStage ?? null,
230
+ source: personRow.source ?? null,
231
+ ownerUserId: personRow.ownerUserId ?? null,
232
+ organizationId: personRow.organizationId ?? null,
233
+ tenantId: personRow.tenantId ?? null,
234
+ createdAt: toIso(personRow.createdAt),
235
+ updatedAt: toIso(personRow.updatedAt)
236
+ },
237
+ profile: profileRow ? {
238
+ id: profileRow.id,
239
+ firstName: profileRow.firstName ?? null,
240
+ lastName: profileRow.lastName ?? null,
241
+ preferredName: profileRow.preferredName ?? null,
242
+ jobTitle: profileRow.jobTitle ?? null,
243
+ department: profileRow.department ?? null,
244
+ seniority: profileRow.seniority ?? null,
245
+ timezone: profileRow.timezone ?? null,
246
+ linkedInUrl: profileRow.linkedInUrl ?? null,
247
+ twitterUrl: profileRow.twitterUrl ?? null,
248
+ companyEntityId: profileRow.companyEntityId ?? null
249
+ } : null,
250
+ customFields,
251
+ related
252
+ };
253
+ }
254
+ };
255
+ const peopleAiTools = [listPeopleTool, getPersonTool];
256
+ var people_pack_default = peopleAiTools;
257
+ export {
258
+ people_pack_default as default,
259
+ peopleAiTools
260
+ };
261
+ //# sourceMappingURL=people-pack.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/customers/ai-tools/people-pack.ts"],
4
+ "sourcesContent": ["/**\n * `customers.list_people` + `customers.get_person` (Phase 1 WS-C, Step 3.9).\n *\n * Read-only tools scoped to `ctx.tenantId` / `ctx.organizationId` that wrap\n * the existing customers query engine + encryption helpers. Mutation tools\n * are deferred to Step 5.13+ under the pending-action contract.\n *\n * Phase 3a of `.ai/specs/2026-04-27-ai-tools-api-backed-dry-refactor.md`:\n * `customers.list_people` is now an API-backed wrapper over\n * `GET /api/customers/people`. The `companyId` AI input has no inclusion\n * equivalent on the route (the route exposes `excludeLinkedCompanyId` only)\n * so it is pre-resolved against `CustomerPersonProfile.company` and threaded\n * through the route's `ids` filter.\n *\n * Phase 3c of the same spec migrates `customers.get_person` to a single\n * in-process call to `GET /api/customers/people/<id>?include=...` (the\n * documented aggregate detail route). Tool name, schema, requiredFeatures,\n * and output shape are unchanged.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { defineApiBackedAiTool } from '@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool'\nimport {\n createAiApiOperationRunner,\n type AiApiOperationRequest,\n type AiToolExecutionContext,\n} from '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerPersonProfile,\n} from '../data/entities'\nimport { assertTenantScope, type CustomersAiToolDefinition, type CustomersToolContext } from './types'\n\nconst NIL_UUID = '00000000-0000-0000-0000-000000000000'\n\nfunction resolveEm(ctx: CustomersToolContext | AiToolExecutionContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nfunction buildScope(ctx: CustomersToolContext | AiToolExecutionContext, tenantId: string) {\n return {\n tenantId,\n organizationId: ctx.organizationId,\n }\n}\n\nconst listPeopleInput = z\n .object({\n q: z.string().trim().optional().describe('Optional search text matched against display name / email / phone. Omit or leave empty to list all.'),\n limit: z.number().int().min(1).max(100).optional().describe('Maximum rows to return (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Number of rows to skip (default 0).'),\n tags: z.array(z.string().uuid()).optional().describe('Restrict to persons carrying at least one of these tag ids.'),\n companyId: z.string().uuid().optional().describe('Restrict to persons linked to the given company entity.'),\n })\n .passthrough()\n\ntype ListPeopleInput = z.infer<typeof listPeopleInput>\n\ntype ListPeopleApiItem = {\n id?: string\n display_name?: string | null\n displayName?: string | null\n primary_email?: string | null\n primaryEmail?: string | null\n primary_phone?: string | null\n primaryPhone?: string | null\n status?: string | null\n lifecycle_stage?: string | null\n lifecycleStage?: string | null\n source?: string | null\n owner_user_id?: string | null\n ownerUserId?: string | null\n organization_id?: string | null\n organizationId?: string | null\n tenant_id?: string | null\n tenantId?: string | null\n created_at?: string | null\n createdAt?: string | null\n}\n\ntype ListPeopleApiResponse = {\n items?: ListPeopleApiItem[]\n total?: number\n}\n\ntype ListPeopleOutput = {\n items: Array<Record<string, unknown>>\n total: number\n limit: number\n offset: number\n}\n\nconst listPeopleTool = defineApiBackedAiTool<ListPeopleInput, ListPeopleApiResponse, ListPeopleOutput>({\n name: 'customers.list_people',\n displayName: 'List people',\n description:\n 'Search / list people (CRM persons) for the caller tenant + organization. Returns { items, total, limit, offset }.',\n inputSchema: listPeopleInput,\n requiredFeatures: ['customers.people.view'],\n toOperation: async (input, ctx) => {\n const { tenantId } = assertTenantScope(ctx as unknown as CustomersToolContext)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const page = Math.floor(offset / limit) + 1\n\n const query: Record<string, string | number | boolean | null | undefined> = {\n page,\n pageSize: limit,\n }\n if (input.q?.trim()) query.search = input.q.trim()\n if (input.tags && input.tags.length > 0) query.tagIds = input.tags.join(',')\n\n if (input.companyId) {\n const em = resolveEm(ctx)\n const profiles = await findWithDecryption<CustomerPersonProfile>(\n em,\n CustomerPersonProfile,\n { tenantId, company: input.companyId } as never,\n undefined,\n buildScope(ctx, tenantId),\n )\n const ids = profiles\n .map((profile) => {\n const entity = (profile as { entity?: unknown }).entity\n if (!entity) return null\n if (typeof entity === 'string') return entity\n const candidate = (entity as { id?: unknown }).id\n return typeof candidate === 'string' ? candidate : null\n })\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n // Empty match \u2014 feed a non-existent uuid so the route returns\n // { items: [], total: 0 } without us bypassing the API.\n query.ids = ids.length ? ids.join(',') : NIL_UUID\n }\n\n const operation: AiApiOperationRequest = {\n method: 'GET',\n path: '/customers/people',\n query,\n }\n return operation\n },\n mapResponse: (response, input) => {\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const data = (response.data ?? {}) as ListPeopleApiResponse\n const rawItems: ListPeopleApiItem[] = Array.isArray(data.items) ? data.items : []\n return {\n items: rawItems.map((row) => {\n const createdAtRaw = row.created_at ?? row.createdAt ?? null\n const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null\n return {\n id: row.id,\n displayName: row.display_name ?? row.displayName ?? null,\n primaryEmail: row.primary_email ?? row.primaryEmail ?? null,\n primaryPhone: row.primary_phone ?? row.primaryPhone ?? null,\n status: row.status ?? null,\n lifecycleStage: row.lifecycle_stage ?? row.lifecycleStage ?? null,\n source: row.source ?? null,\n ownerUserId: row.owner_user_id ?? row.ownerUserId ?? null,\n organizationId: row.organization_id ?? row.organizationId ?? null,\n tenantId: row.tenant_id ?? row.tenantId ?? null,\n createdAt,\n }\n }),\n total: typeof data.total === 'number' ? data.total : 0,\n limit,\n offset,\n }\n },\n}) as unknown as CustomersAiToolDefinition\n\nconst getPersonInput = z.object({\n personId: z.string().uuid().describe('Person entity id (UUID).'),\n includeRelated: z\n .boolean()\n .optional()\n .describe('When true, include notes, activities, deals, addresses, tasks, and tags (each capped at 100).'),\n})\n\ntype GetPersonInput = z.infer<typeof getPersonInput>\n\ntype ApiPersonDetailRow = Record<string, unknown> | null | undefined\n\nfunction toIso(value: unknown): string | null {\n if (!value) return null\n const dt = value instanceof Date ? value : new Date(String(value))\n if (Number.isNaN(dt.getTime())) return null\n return dt.toISOString()\n}\n\nconst getPersonTool: CustomersAiToolDefinition = {\n name: 'customers.get_person',\n displayName: 'Get person',\n description:\n 'Fetch a person customer record by id with profile fields and (optionally) notes, activities, deals, addresses, tasks, tags, and custom fields. Returns { found: false } when the record is outside tenant/org scope or missing.',\n inputSchema: getPersonInput,\n requiredFeatures: ['customers.people.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: GetPersonInput = getPersonInput.parse(rawInput)\n const includeRelated = !!input.includeRelated\n\n const operation: AiApiOperationRequest = {\n method: 'GET',\n path: `/customers/people/${input.personId}`,\n }\n if (includeRelated) {\n operation.query = { include: 'addresses,comments,activities,interactions,deals,todos' }\n }\n\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n const response = await runner.run<Record<string, unknown>>(operation)\n if (!response.success) {\n if (response.statusCode === 404 || response.statusCode === 403) {\n return { found: false as const, personId: input.personId }\n }\n throw new Error(response.error ?? `Failed to fetch person ${input.personId}`)\n }\n const data = (response.data ?? {}) as Record<string, unknown>\n const personRow = (data.person ?? null) as ApiPersonDetailRow\n if (!personRow) {\n return { found: false as const, personId: input.personId }\n }\n const profileRow = (data.profile ?? null) as ApiPersonDetailRow\n const customFields = (data.customFields ?? {}) as Record<string, unknown>\n\n let related: Record<string, unknown> | null = null\n if (includeRelated) {\n const addresses = Array.isArray(data.addresses) ? (data.addresses as Array<Record<string, unknown>>) : []\n const activities = Array.isArray(data.activities) ? (data.activities as Array<Record<string, unknown>>) : []\n const notes = Array.isArray(data.comments) ? (data.comments as Array<Record<string, unknown>>) : []\n const todos = Array.isArray(data.todos) ? (data.todos as Array<Record<string, unknown>>) : []\n const interactions = Array.isArray(data.interactions) ? (data.interactions as Array<Record<string, unknown>>) : []\n const tagsRows = Array.isArray(data.tags) ? (data.tags as Array<Record<string, unknown>>) : []\n const dealsRows = Array.isArray(data.deals) ? (data.deals as Array<Record<string, unknown>>) : []\n related = {\n addresses: addresses.map((address) => ({\n id: address.id,\n name: address.name ?? null,\n purpose: address.purpose ?? null,\n addressLine1: address.addressLine1 ?? null,\n addressLine2: address.addressLine2 ?? null,\n city: address.city ?? null,\n region: address.region ?? null,\n postalCode: address.postalCode ?? null,\n country: address.country ?? null,\n isPrimary: !!address.isPrimary,\n })),\n activities: activities.map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: toIso(activity.occurredAt),\n createdAt: toIso(activity.createdAt),\n })),\n notes: notes.map((comment) => ({\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId ?? null,\n createdAt: toIso(comment.createdAt),\n })),\n tasks: todos.map((task) => ({\n id: task.id,\n todoId: task.todoId ?? task.id,\n todoSource: task.todoSource ?? null,\n createdAt: toIso(task.createdAt),\n })),\n interactions: interactions.map((interaction) => ({\n id: interaction.id,\n interactionType: interaction.interactionType,\n title: interaction.title ?? null,\n status: interaction.status,\n scheduledAt: toIso(interaction.scheduledAt),\n occurredAt: toIso(interaction.occurredAt),\n })),\n tags: tagsRows\n .map((tag) => {\n if (!tag || typeof tag !== 'object') return null\n const id = typeof tag.id === 'string' ? tag.id : null\n const label = typeof tag.label === 'string' ? tag.label : null\n if (!id || !label) return null\n const slug = typeof tag.slug === 'string' ? tag.slug : label\n const color = typeof tag.color === 'string' ? tag.color : null\n return { id, slug, label, color }\n })\n .filter(\n (entry): entry is { id: string; slug: string; label: string; color: string | null } =>\n entry !== null,\n ),\n deals: dealsRows\n .map((deal) => {\n if (!deal || typeof deal !== 'object') return null\n const id = typeof deal.id === 'string' ? deal.id : null\n if (!id) return null\n return {\n id,\n title: typeof deal.title === 'string' ? deal.title : '',\n status: typeof deal.status === 'string' ? deal.status : null,\n pipelineStageId:\n typeof deal.pipelineStageId === 'string' ? deal.pipelineStageId : null,\n valueAmount:\n typeof deal.valueAmount === 'string'\n ? deal.valueAmount\n : deal.valueAmount === null || deal.valueAmount === undefined\n ? null\n : String(deal.valueAmount),\n valueCurrency:\n typeof deal.valueCurrency === 'string' ? deal.valueCurrency : null,\n }\n })\n .filter(\n (\n value,\n ): value is {\n id: string\n title: string\n status: string | null\n pipelineStageId: string | null\n valueAmount: string | null\n valueCurrency: string | null\n } => value !== null,\n ),\n }\n }\n\n return {\n found: true as const,\n person: {\n id: personRow.id,\n displayName: personRow.displayName ?? null,\n description: personRow.description ?? null,\n primaryEmail: personRow.primaryEmail ?? null,\n primaryPhone: personRow.primaryPhone ?? null,\n status: personRow.status ?? null,\n lifecycleStage: personRow.lifecycleStage ?? null,\n source: personRow.source ?? null,\n ownerUserId: personRow.ownerUserId ?? null,\n organizationId: personRow.organizationId ?? null,\n tenantId: personRow.tenantId ?? null,\n createdAt: toIso(personRow.createdAt),\n updatedAt: toIso(personRow.updatedAt),\n },\n profile: profileRow\n ? {\n id: profileRow.id,\n firstName: profileRow.firstName ?? null,\n lastName: profileRow.lastName ?? null,\n preferredName: profileRow.preferredName ?? null,\n jobTitle: profileRow.jobTitle ?? null,\n department: profileRow.department ?? null,\n seniority: profileRow.seniority ?? null,\n timezone: profileRow.timezone ?? null,\n linkedInUrl: profileRow.linkedInUrl ?? null,\n twitterUrl: profileRow.twitterUrl ?? null,\n companyEntityId: profileRow.companyEntityId ?? null,\n }\n : null,\n customFields,\n related,\n }\n },\n}\n\nexport const peopleAiTools: CustomersAiToolDefinition[] = [listPeopleTool, getPersonTool]\n\nexport default peopleAiTools\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,102 @@
1
+ import { z } from "zod";
2
+ import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
3
+ import {
4
+ CustomerDictionaryEntry,
5
+ CustomerPipeline,
6
+ CustomerPipelineStage,
7
+ CustomerSettings
8
+ } from "../data/entities.js";
9
+ import { assertTenantScope } from "./types.js";
10
+ function resolveEm(ctx) {
11
+ return ctx.container.resolve("em");
12
+ }
13
+ function buildScope(ctx, tenantId) {
14
+ return { tenantId, organizationId: ctx.organizationId };
15
+ }
16
+ const getSettingsInput = z.object({}).passthrough();
17
+ const getSettingsTool = {
18
+ name: "customers.get_settings",
19
+ displayName: "Get customers module settings",
20
+ description: "Return the customers module settings for the caller scope: pipelines, pipeline stages, dictionaries (grouped by kind), and address format.",
21
+ inputSchema: getSettingsInput,
22
+ requiredFeatures: ["customers.settings.manage"],
23
+ tags: ["read", "customers"],
24
+ handler: async (_rawInput, ctx) => {
25
+ const { tenantId } = assertTenantScope(ctx);
26
+ const em = resolveEm(ctx);
27
+ const where = { tenantId };
28
+ if (ctx.organizationId) where.organizationId = ctx.organizationId;
29
+ const [pipelines, stages, dictionaryEntries, settings] = await Promise.all([
30
+ findWithDecryption(
31
+ em,
32
+ CustomerPipeline,
33
+ where,
34
+ { orderBy: { createdAt: "asc" } },
35
+ buildScope(ctx, tenantId)
36
+ ),
37
+ findWithDecryption(
38
+ em,
39
+ CustomerPipelineStage,
40
+ where,
41
+ { orderBy: { pipelineId: "asc", order: "asc" } },
42
+ buildScope(ctx, tenantId)
43
+ ),
44
+ findWithDecryption(
45
+ em,
46
+ CustomerDictionaryEntry,
47
+ where,
48
+ { orderBy: { kind: "asc", label: "asc" } },
49
+ buildScope(ctx, tenantId)
50
+ ),
51
+ ctx.organizationId ? findOneWithDecryption(
52
+ em,
53
+ CustomerSettings,
54
+ { tenantId, organizationId: ctx.organizationId },
55
+ void 0,
56
+ buildScope(ctx, tenantId)
57
+ ) : null
58
+ ]);
59
+ const pipelineRows = pipelines.filter((row) => row.tenantId === tenantId);
60
+ const stageRows = stages.filter((row) => row.tenantId === tenantId);
61
+ const dictionaryRows = dictionaryEntries.filter((row) => row.tenantId === tenantId);
62
+ const dictionaries = {};
63
+ for (const row of dictionaryRows) {
64
+ const bucket = dictionaries[row.kind] ?? (dictionaries[row.kind] = []);
65
+ bucket.push({
66
+ id: row.id,
67
+ value: row.value,
68
+ label: row.label,
69
+ normalizedValue: row.normalizedValue,
70
+ color: row.color ?? null,
71
+ icon: row.icon ?? null
72
+ });
73
+ }
74
+ return {
75
+ pipelines: pipelineRows.map((row) => ({
76
+ id: row.id,
77
+ name: row.name,
78
+ isDefault: !!row.isDefault,
79
+ organizationId: row.organizationId ?? null,
80
+ tenantId: row.tenantId ?? null,
81
+ createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null
82
+ })),
83
+ pipelineStages: stageRows.map((row) => ({
84
+ id: row.id,
85
+ pipelineId: row.pipelineId,
86
+ label: row.label,
87
+ order: row.order,
88
+ organizationId: row.organizationId ?? null,
89
+ tenantId: row.tenantId ?? null
90
+ })),
91
+ dictionaries,
92
+ addressFormat: settings?.addressFormat ?? "line_first"
93
+ };
94
+ }
95
+ };
96
+ const settingsAiTools = [getSettingsTool];
97
+ var settings_pack_default = settingsAiTools;
98
+ export {
99
+ settings_pack_default as default,
100
+ settingsAiTools
101
+ };
102
+ //# sourceMappingURL=settings-pack.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/customers/ai-tools/settings-pack.ts"],
4
+ "sourcesContent": ["/**\n * `customers.get_settings` (Phase 1 WS-C, Step 3.9).\n *\n * Aggregates the four settings surfaces the spec calls out: pipelines,\n * pipeline stages, dictionaries, and address-format settings. All reads are\n * tenant + organization scoped through the existing encryption helpers.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerDictionaryEntry,\n CustomerPipeline,\n CustomerPipelineStage,\n CustomerSettings,\n} from '../data/entities'\nimport { assertTenantScope, type CustomersAiToolDefinition, type CustomersToolContext } from './types'\n\nfunction resolveEm(ctx: CustomersToolContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nfunction buildScope(ctx: CustomersToolContext, tenantId: string) {\n return { tenantId, organizationId: ctx.organizationId }\n}\n\nconst getSettingsInput = z.object({}).passthrough()\n\nconst getSettingsTool: CustomersAiToolDefinition = {\n name: 'customers.get_settings',\n displayName: 'Get customers module settings',\n description:\n 'Return the customers module settings for the caller scope: pipelines, pipeline stages, dictionaries (grouped by kind), and address format.',\n inputSchema: getSettingsInput,\n requiredFeatures: ['customers.settings.manage'],\n tags: ['read', 'customers'],\n handler: async (_rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const em = resolveEm(ctx)\n const where: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const [pipelines, stages, dictionaryEntries, settings] = await Promise.all([\n findWithDecryption<CustomerPipeline>(\n em,\n CustomerPipeline,\n where as any,\n { orderBy: { createdAt: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n findWithDecryption<CustomerPipelineStage>(\n em,\n CustomerPipelineStage,\n where as any,\n { orderBy: { pipelineId: 'asc', order: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n findWithDecryption<CustomerDictionaryEntry>(\n em,\n CustomerDictionaryEntry,\n where as any,\n { orderBy: { kind: 'asc', label: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n ctx.organizationId\n ? findOneWithDecryption<CustomerSettings>(\n em,\n CustomerSettings,\n { tenantId, organizationId: ctx.organizationId } as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n : null,\n ])\n const pipelineRows = pipelines.filter((row) => row.tenantId === tenantId)\n const stageRows = stages.filter((row) => row.tenantId === tenantId)\n const dictionaryRows = dictionaryEntries.filter((row) => row.tenantId === tenantId)\n const dictionaries: Record<string, Array<{\n id: string\n value: string\n label: string\n normalizedValue: string\n color: string | null\n icon: string | null\n }>> = {}\n for (const row of dictionaryRows) {\n const bucket = dictionaries[row.kind] ?? (dictionaries[row.kind] = [])\n bucket.push({\n id: row.id,\n value: row.value,\n label: row.label,\n normalizedValue: row.normalizedValue,\n color: row.color ?? null,\n icon: row.icon ?? null,\n })\n }\n return {\n pipelines: pipelineRows.map((row) => ({\n id: row.id,\n name: row.name,\n isDefault: !!row.isDefault,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n pipelineStages: stageRows.map((row) => ({\n id: row.id,\n pipelineId: row.pipelineId,\n label: row.label,\n order: row.order,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n })),\n dictionaries,\n addressFormat: settings?.addressFormat ?? 'line_first',\n }\n },\n}\n\nexport const settingsAiTools: CustomersAiToolDefinition[] = [getSettingsTool]\n\nexport default settingsAiTools\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ function assertTenantScope(ctx) {
2
+ if (!ctx.tenantId) {
3
+ throw new Error("Tenant context is required for customers.* tools");
4
+ }
5
+ return { tenantId: ctx.tenantId, organizationId: ctx.organizationId };
6
+ }
7
+ export {
8
+ assertTenantScope
9
+ };
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/customers/ai-tools/types.ts"],
4
+ "sourcesContent": ["/**\n * Local AI tool shape for the customers module (Phase 1 WS-C, Step 3.9).\n *\n * The customers module declares its read-only tool pack directly as plain\n * objects so jest can load it without pulling `@open-mercato/ai-assistant`\n * into the core package's module graph. This mirrors the pattern used by\n * `packages/core/src/modules/inbox_ops/ai-tools.ts`. The shape is a strict\n * subset of `AiToolDefinition` from `@open-mercato/ai-assistant`; the\n * generator walks every module root for a default/aiTools export with this\n * shape.\n */\nimport type { z } from 'zod'\nimport type { AwilixContainer } from 'awilix'\n\nexport interface CustomersToolContext {\n tenantId: string | null\n organizationId: string | null\n userId: string | null\n container: AwilixContainer\n userFeatures: string[]\n isSuperAdmin: boolean\n apiKeySecret?: string\n sessionId?: string\n}\n\n/**\n * Shape returned by `loadBeforeRecord` on a mutation tool. Mirrors\n * `AiToolLoadBeforeSingleRecord` from `@open-mercato/ai-assistant/lib/types`;\n * the customers module deliberately does not import that package so we keep a\n * local prefix-compatible declaration (same rule as `CustomersAiToolDefinition`).\n */\nexport interface CustomersToolLoadBeforeSingleRecord {\n recordId: string\n entityType: string\n recordVersion: string | null\n before: Record<string, unknown>\n}\n\nexport interface CustomersAiToolDefinition<TInput = unknown, TOutput = unknown> {\n name: string\n displayName?: string\n description: string\n inputSchema: z.ZodType<TInput>\n requiredFeatures?: string[]\n tags?: string[]\n isMutation?: boolean\n /**\n * Marks the mutation as destructive \u2014 gates the call through the\n * approval card under `destructive-confirm-required` policy. Accepts a\n * static boolean (whole tool destructive) or a predicate\n * `(input) => boolean` evaluated at every call so a multi-operation\n * tool (e.g. `manage_deal_comment` with create/update/delete) gates\n * only the destructive branches. Default `false`. See\n * `@open-mercato/ai-assistant` framework `AiToolDefinition.isDestructive`\n * for the canonical definition; this surface mirrors the contract for\n * type-safe authoring inside the customers module.\n */\n isDestructive?: boolean | ((input: TInput) => boolean)\n maxCallsPerTurn?: number\n supportsAttachments?: boolean\n handler: (input: TInput, context: CustomersToolContext) => Promise<TOutput>\n loadBeforeRecord?: (\n input: TInput,\n context: CustomersToolContext,\n ) => Promise<CustomersToolLoadBeforeSingleRecord | null>\n}\n\nexport function assertTenantScope(ctx: CustomersToolContext): {\n tenantId: string\n organizationId: string | null\n} {\n if (!ctx.tenantId) {\n throw new Error('Tenant context is required for customers.* tools')\n }\n return { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n}\n"],
5
+ "mappings": "AAmEO,SAAS,kBAAkB,KAGhC;AACA,MAAI,CAAC,IAAI,UAAU;AACjB,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,SAAO,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AACtE;",
6
+ "names": []
7
+ }
@@ -0,0 +1,20 @@
1
+ import peopleAiTools from "./ai-tools/people-pack.js";
2
+ import companiesAiTools from "./ai-tools/companies-pack.js";
3
+ import dealsAiTools from "./ai-tools/deals-pack.js";
4
+ import activitiesTasksAiTools from "./ai-tools/activities-tasks-pack.js";
5
+ import addressesTagsAiTools from "./ai-tools/addresses-tags-pack.js";
6
+ import settingsAiTools from "./ai-tools/settings-pack.js";
7
+ const aiTools = [
8
+ ...peopleAiTools,
9
+ ...companiesAiTools,
10
+ ...dealsAiTools,
11
+ ...activitiesTasksAiTools,
12
+ ...addressesTagsAiTools,
13
+ ...settingsAiTools
14
+ ];
15
+ var ai_tools_default = aiTools;
16
+ export {
17
+ aiTools,
18
+ ai_tools_default as default
19
+ };
20
+ //# sourceMappingURL=ai-tools.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/customers/ai-tools.ts"],
4
+ "sourcesContent": ["/**\n * Module-root AI tool contribution for the customers module\n * (Phase 1 WS-C, Step 3.9 \u2014 read-only Phase 1 surface).\n *\n * The generator walks every module for a top-level `ai-tools.ts` and takes\n * the default/`aiTools` export as the contribution. This file aggregates the\n * six customers packs (people, companies, deals, activities+tasks,\n * addresses+tags, settings) so they all flow through the existing\n * `ai-tools.generated.ts` pipeline without any generator changes.\n *\n * Mutation tools are deferred to Step 5.13+ under the pending-action contract;\n * every tool here is read-only and enforces tenant + organization scoping via\n * the existing encryption helpers. See\n * `.ai/runs/2026-04-18-ai-framework-unification/step-3.9-checks.md` for the\n * matrix of required features and decisions.\n */\nimport peopleAiTools from './ai-tools/people-pack'\nimport companiesAiTools from './ai-tools/companies-pack'\nimport dealsAiTools from './ai-tools/deals-pack'\nimport activitiesTasksAiTools from './ai-tools/activities-tasks-pack'\nimport addressesTagsAiTools from './ai-tools/addresses-tags-pack'\nimport settingsAiTools from './ai-tools/settings-pack'\nimport type { CustomersAiToolDefinition } from './ai-tools/types'\n\nexport const aiTools: CustomersAiToolDefinition[] = [\n ...peopleAiTools,\n ...companiesAiTools,\n ...dealsAiTools,\n ...activitiesTasksAiTools,\n ...addressesTagsAiTools,\n ...settingsAiTools,\n]\n\nexport default aiTools\n"],
5
+ "mappings": "AAgBA,OAAO,mBAAmB;AAC1B,OAAO,sBAAsB;AAC7B,OAAO,kBAAkB;AACzB,OAAO,4BAA4B;AACnC,OAAO,0BAA0B;AACjC,OAAO,qBAAqB;AAGrB,MAAM,UAAuC;AAAA,EAClD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,IAAO,mBAAQ;",
6
+ "names": []
7
+ }