@open-mercato/core 0.6.6-develop.6515.1.01911d00e2 → 0.6.6-develop.6519.1.bdc91fb755
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/configs/lib/upgrade-actions.js +31 -1
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js +11 -2
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +3 -2
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/context.js +4 -2
- package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +2 -1
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +7 -2
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +3 -2
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/cli.js +19 -0
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +8 -3
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/shared.js +2 -1
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +5 -0
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +5 -0
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesCard.js +3 -2
- package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityCard.js +2 -1
- package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js +3 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
- package/dist/modules/customers/components/detail/TaskDialog.js +3 -2
- package/dist/modules/customers/components/detail/TaskDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/TaskForm.js +170 -69
- package/dist/modules/customers/components/detail/TaskForm.js.map +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js +27 -4
- package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/data/enrichers.js +2 -2
- package/dist/modules/customers/data/enrichers.js.map +2 -2
- package/dist/modules/customers/data/validators.js +6 -2
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/lib/dictionaries.js +2 -1
- package/dist/modules/customers/lib/dictionaries.js.map +2 -2
- package/dist/modules/customers/lib/interactionProjection.js +2 -1
- package/dist/modules/customers/lib/interactionProjection.js.map +2 -2
- package/dist/modules/customers/lib/interactionStatus.js +24 -0
- package/dist/modules/customers/lib/interactionStatus.js.map +7 -0
- package/dist/modules/customers/lib/link-channel-message-handler.js +4 -5
- package/dist/modules/customers/lib/link-channel-message-handler.js.map +2 -2
- package/dist/modules/dictionaries/components/AppearanceSelector.js +7 -3
- package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +1 -0
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/configs/lib/upgrade-actions.ts +31 -1
- package/src/modules/customers/ai-tools/activities-tasks-pack.ts +12 -3
- package/src/modules/customers/api/companies/[id]/route.ts +3 -2
- package/src/modules/customers/api/dictionaries/context.ts +2 -0
- package/src/modules/customers/api/interactions/conflicts/route.ts +2 -1
- package/src/modules/customers/api/interactions/counts/route.ts +7 -2
- package/src/modules/customers/api/people/[id]/route.ts +3 -2
- package/src/modules/customers/cli.ts +19 -0
- package/src/modules/customers/commands/interactions.ts +8 -3
- package/src/modules/customers/commands/shared.ts +1 -0
- package/src/modules/customers/components/DictionarySettings.tsx +5 -0
- package/src/modules/customers/components/DictionarySortSettings.tsx +5 -0
- package/src/modules/customers/components/detail/ActivitiesCard.tsx +3 -2
- package/src/modules/customers/components/detail/ActivityCard.tsx +2 -1
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -2
- package/src/modules/customers/components/detail/TaskDialog.tsx +4 -1
- package/src/modules/customers/components/detail/TaskForm.tsx +218 -71
- package/src/modules/customers/components/detail/TasksSection.tsx +28 -2
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +1 -0
- package/src/modules/customers/data/enrichers.ts +2 -7
- package/src/modules/customers/data/validators.ts +16 -2
- package/src/modules/customers/i18n/de.json +10 -0
- package/src/modules/customers/i18n/en.json +10 -0
- package/src/modules/customers/i18n/es.json +10 -0
- package/src/modules/customers/i18n/pl.json +10 -0
- package/src/modules/customers/lib/dictionaries.ts +1 -0
- package/src/modules/customers/lib/interactionProjection.ts +6 -2
- package/src/modules/customers/lib/interactionStatus.ts +30 -0
- package/src/modules/customers/lib/link-channel-message-handler.ts +4 -5
- package/src/modules/dictionaries/components/AppearanceSelector.tsx +10 -1
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +1 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -10,7 +10,37 @@ function compareVersions(a, b) {
|
|
|
10
10
|
}
|
|
11
11
|
return semver.compare(cleanA, cleanB);
|
|
12
12
|
}
|
|
13
|
-
const upgradeActions = [
|
|
13
|
+
const upgradeActions = [
|
|
14
|
+
{
|
|
15
|
+
id: "customers.seed-interaction-statuses",
|
|
16
|
+
version: "0.6.5",
|
|
17
|
+
messageKey: "customers.config.upgradeActions.interactionStatuses.message",
|
|
18
|
+
ctaKey: "customers.config.upgradeActions.interactionStatuses.cta",
|
|
19
|
+
successKey: "customers.config.upgradeActions.interactionStatuses.success",
|
|
20
|
+
loadingKey: "customers.config.upgradeActions.interactionStatuses.loading",
|
|
21
|
+
// Existing tenants predate the `interaction_status` dictionary, so their status
|
|
22
|
+
// dropdown is empty until seeded. New tenants get it via customers `seedDefaults`.
|
|
23
|
+
// Lazy-imported so configs stays decoupled from customers (the catalog of actions
|
|
24
|
+
// lives here, but customers code only loads when the action actually runs).
|
|
25
|
+
run: async ({ em, tenantId, organizationId }) => {
|
|
26
|
+
const [{ INTERACTION_STATUS_DEFAULTS }, { ensureDictionaryEntry }] = await Promise.all([
|
|
27
|
+
import("@open-mercato/core/modules/customers/cli"),
|
|
28
|
+
import("@open-mercato/core/modules/customers/commands/shared")
|
|
29
|
+
]);
|
|
30
|
+
for (const entry of INTERACTION_STATUS_DEFAULTS) {
|
|
31
|
+
await ensureDictionaryEntry(em, {
|
|
32
|
+
tenantId,
|
|
33
|
+
organizationId,
|
|
34
|
+
kind: "interaction_status",
|
|
35
|
+
value: entry.value,
|
|
36
|
+
label: entry.label,
|
|
37
|
+
color: entry.color,
|
|
38
|
+
icon: entry.icon
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
];
|
|
14
44
|
function actionsUpToVersion(version) {
|
|
15
45
|
return upgradeActions.filter((action) => compareVersions(action.version, version) <= 0).sort((a, b) => compareVersions(a.version, b.version) || a.id.localeCompare(b.id));
|
|
16
46
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/configs/lib/upgrade-actions.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport * as semver from 'semver'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\n\nexport type UpgradeActionContext = {\n tenantId: string\n organizationId: string\n container: AppContainer\n em: EntityManager\n}\n\nexport type UpgradeActionDefinition = {\n id: string\n version: string\n messageKey: string\n ctaKey: string\n successKey: string\n loadingKey?: string\n run: (ctx: UpgradeActionContext) => Promise<void>\n}\n\n/**\n * Compare two semantic version strings.\n * Uses the semver library for robust version comparison.\n * Returns negative if a < b, positive if a > b, 0 if equal.\n * Throws an error if either version string is invalid.\n */\nexport function compareVersions(a: string, b: string): number {\n const cleanA = semver.valid(semver.coerce(a))\n const cleanB = semver.valid(semver.coerce(b))\n if (!cleanA) {\n throw new Error(`Invalid version string: \"${a}\". Expected a valid semver format (e.g., \"1.2.3\").`)\n }\n if (!cleanB) {\n throw new Error(`Invalid version string: \"${b}\". Expected a valid semver format (e.g., \"1.2.3\").`)\n }\n return semver.compare(cleanA, cleanB)\n}\n\nexport const upgradeActions: UpgradeActionDefinition[] = []\n\nexport function actionsUpToVersion(version: string): UpgradeActionDefinition[] {\n return upgradeActions // NOSONAR \u2014 upgradeActions is populated at boot time by modules\n .filter((action) => compareVersions(action.version, version) <= 0)\n .sort((a, b) => compareVersions(a.version, b.version) || a.id.localeCompare(b.id))\n}\n\nexport function findUpgradeAction(actionId: string, maxVersion: string): UpgradeActionDefinition | undefined {\n const matches = actionsUpToVersion(maxVersion).filter((action) => action.id === actionId)\n if (!matches.length) return undefined\n return matches[matches.length - 1]\n}\n"],
|
|
5
|
-
"mappings": "AACA,YAAY,YAAY;AA0BjB,SAAS,gBAAgB,GAAW,GAAmB;AAC5D,QAAM,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC,CAAC;AAC5C,QAAM,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC,CAAC;AAC5C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,4BAA4B,CAAC,oDAAoD;AAAA,EACnG;AACA,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,4BAA4B,CAAC,oDAAoD;AAAA,EACnG;AACA,SAAO,OAAO,QAAQ,QAAQ,MAAM;AACtC;AAEO,MAAM,iBAA4C,CAAC;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport * as semver from 'semver'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\n\nexport type UpgradeActionContext = {\n tenantId: string\n organizationId: string\n container: AppContainer\n em: EntityManager\n}\n\nexport type UpgradeActionDefinition = {\n id: string\n version: string\n messageKey: string\n ctaKey: string\n successKey: string\n loadingKey?: string\n run: (ctx: UpgradeActionContext) => Promise<void>\n}\n\n/**\n * Compare two semantic version strings.\n * Uses the semver library for robust version comparison.\n * Returns negative if a < b, positive if a > b, 0 if equal.\n * Throws an error if either version string is invalid.\n */\nexport function compareVersions(a: string, b: string): number {\n const cleanA = semver.valid(semver.coerce(a))\n const cleanB = semver.valid(semver.coerce(b))\n if (!cleanA) {\n throw new Error(`Invalid version string: \"${a}\". Expected a valid semver format (e.g., \"1.2.3\").`)\n }\n if (!cleanB) {\n throw new Error(`Invalid version string: \"${b}\". Expected a valid semver format (e.g., \"1.2.3\").`)\n }\n return semver.compare(cleanA, cleanB)\n}\n\nexport const upgradeActions: UpgradeActionDefinition[] = [\n {\n id: 'customers.seed-interaction-statuses',\n version: '0.6.5',\n messageKey: 'customers.config.upgradeActions.interactionStatuses.message',\n ctaKey: 'customers.config.upgradeActions.interactionStatuses.cta',\n successKey: 'customers.config.upgradeActions.interactionStatuses.success',\n loadingKey: 'customers.config.upgradeActions.interactionStatuses.loading',\n // Existing tenants predate the `interaction_status` dictionary, so their status\n // dropdown is empty until seeded. New tenants get it via customers `seedDefaults`.\n // Lazy-imported so configs stays decoupled from customers (the catalog of actions\n // lives here, but customers code only loads when the action actually runs).\n run: async ({ em, tenantId, organizationId }) => {\n const [{ INTERACTION_STATUS_DEFAULTS }, { ensureDictionaryEntry }] = await Promise.all([\n import('@open-mercato/core/modules/customers/cli'),\n import('@open-mercato/core/modules/customers/commands/shared'),\n ])\n for (const entry of INTERACTION_STATUS_DEFAULTS) {\n await ensureDictionaryEntry(em, {\n tenantId,\n organizationId,\n kind: 'interaction_status',\n value: entry.value,\n label: entry.label,\n color: entry.color,\n icon: entry.icon,\n })\n }\n },\n },\n]\n\nexport function actionsUpToVersion(version: string): UpgradeActionDefinition[] {\n return upgradeActions // NOSONAR \u2014 upgradeActions is populated at boot time by modules\n .filter((action) => compareVersions(action.version, version) <= 0)\n .sort((a, b) => compareVersions(a.version, b.version) || a.id.localeCompare(b.id))\n}\n\nexport function findUpgradeAction(actionId: string, maxVersion: string): UpgradeActionDefinition | undefined {\n const matches = actionsUpToVersion(maxVersion).filter((action) => action.id === actionId)\n if (!matches.length) return undefined\n return matches[matches.length - 1]\n}\n"],
|
|
5
|
+
"mappings": "AACA,YAAY,YAAY;AA0BjB,SAAS,gBAAgB,GAAW,GAAmB;AAC5D,QAAM,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC,CAAC;AAC5C,QAAM,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC,CAAC;AAC5C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,4BAA4B,CAAC,oDAAoD;AAAA,EACnG;AACA,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,4BAA4B,CAAC,oDAAoD;AAAA,EACnG;AACA,SAAO,OAAO,QAAQ,QAAQ,MAAM;AACtC;AAEO,MAAM,iBAA4C;AAAA,EACvD;AAAA,IACE,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,IAKZ,KAAK,OAAO,EAAE,IAAI,UAAU,eAAe,MAAM;AAC/C,YAAM,CAAC,EAAE,4BAA4B,GAAG,EAAE,sBAAsB,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QACrF,OAAO,0CAA0C;AAAA,QACjD,OAAO,sDAAsD;AAAA,MAC/D,CAAC;AACD,iBAAW,SAAS,6BAA6B;AAC/C,cAAM,sBAAsB,IAAI;AAAA,UAC9B;AAAA,UACA;AAAA,UACA,MAAM;AAAA,UACN,OAAO,MAAM;AAAA,UACb,OAAO,MAAM;AAAA,UACb,OAAO,MAAM;AAAA,UACb,MAAM,MAAM;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,mBAAmB,SAA4C;AAC7E,SAAO,eACJ,OAAO,CAAC,WAAW,gBAAgB,OAAO,SAAS,OAAO,KAAK,CAAC,EAChE,KAAK,CAAC,GAAG,MAAM,gBAAgB,EAAE,SAAS,EAAE,OAAO,KAAK,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC;AACrF;AAEO,SAAS,kBAAkB,UAAkB,YAAyD;AAC3G,QAAM,UAAU,mBAAmB,UAAU,EAAE,OAAO,CAAC,WAAW,OAAO,OAAO,QAAQ;AACxF,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,SAAO,QAAQ,QAAQ,SAAS,CAAC;AACnC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
createAiApiOperationRunner
|
|
4
4
|
} from "@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner";
|
|
5
5
|
import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
6
|
+
import { TERMINAL_INTERACTION_STATUS_LIST } from "../lib/interactionStatus.js";
|
|
6
7
|
import {
|
|
7
8
|
CustomerActivity,
|
|
8
9
|
CustomerComment,
|
|
@@ -175,7 +176,7 @@ const listTasksInput = z.object({
|
|
|
175
176
|
personId: z.string().uuid().optional().describe("Restrict to tasks linked to this person entity id."),
|
|
176
177
|
companyId: z.string().uuid().optional().describe("Restrict to tasks linked to this company entity id."),
|
|
177
178
|
dealId: z.string().uuid().optional().describe("Restrict to tasks connected to this deal id."),
|
|
178
|
-
status: z.enum(["open", "done", "cancelled"]).optional().describe(
|
|
179
|
+
status: z.enum(["open", "in_progress", "waiting", "done", "canceled", "cancelled"]).optional().describe('Filter canonical interaction tasks by status. "open" matches every non-terminal status (planned/in_progress/waiting and custom statuses). "cancelled" is accepted as an alias for "canceled". Ignored when listing legacy todo links.'),
|
|
179
180
|
limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
|
|
180
181
|
offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
|
|
181
182
|
}).passthrough();
|
|
@@ -201,7 +202,15 @@ const listTasksTool = {
|
|
|
201
202
|
if (ctx.organizationId) interactionWhere.organizationId = ctx.organizationId;
|
|
202
203
|
if (entityId) interactionWhere.entity = entityId;
|
|
203
204
|
if (input.dealId) interactionWhere.dealId = input.dealId;
|
|
204
|
-
if (input.status)
|
|
205
|
+
if (input.status) {
|
|
206
|
+
if (input.status === "open") {
|
|
207
|
+
interactionWhere.status = { $nin: [...TERMINAL_INTERACTION_STATUS_LIST] };
|
|
208
|
+
} else if (input.status === "cancelled") {
|
|
209
|
+
interactionWhere.status = "canceled";
|
|
210
|
+
} else {
|
|
211
|
+
interactionWhere.status = input.status;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
205
214
|
const interactionRows = await findWithDecryption(
|
|
206
215
|
em,
|
|
207
216
|
CustomerInteraction,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/ai-tools/activities-tasks-pack.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * `customers.list_activities` + `customers.list_tasks` (Phase 1 WS-C, Step 3.9)\n * plus the deal comment / activity manage tools (Phase 3 WS-C, follow-up).\n *\n * The mutation tools route every write through the AI pending-action approval\n * gate via `createAiApiOperationRunner` \u2014 same contract as\n * `customers.update_deal_stage`.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport {\n createAiApiOperationRunner,\n type AiToolExecutionContext,\n} from '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerActivity,\n CustomerComment,\n CustomerDeal,\n CustomerDealCompanyLink,\n CustomerDealPersonLink,\n CustomerInteraction,\n CustomerTodoLink,\n} from '../data/entities'\nimport {\n assertTenantScope,\n type CustomersAiToolDefinition,\n type CustomersToolContext,\n type CustomersToolLoadBeforeSingleRecord,\n} from './types'\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 { tenantId, organizationId: ctx.organizationId }\n}\n\nfunction recordVersionFromUpdatedAt(updatedAt: Date | null | undefined): string | null {\n if (!updatedAt) return null\n const value = updatedAt instanceof Date ? updatedAt : new Date(updatedAt)\n if (Number.isNaN(value.getTime())) return null\n return value.toISOString()\n}\n\n// LLMs frequently emit `\"\"` for \"not provided\" \u2014 coerce blanks (and surrounding\n// whitespace) to `undefined` BEFORE per-field validators run. Mirrors the\n// `blankToUndefined` helper in deals-pack.ts.\nconst blankToUndefined = (value: unknown): unknown => {\n if (typeof value !== 'string') return value\n const trimmed = value.trim()\n return trimmed.length === 0 ? undefined : trimmed\n}\n\nasync function loadDealForScope(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n dealId: string,\n): Promise<CustomerDeal | null> {\n const where: Record<string, unknown> = { id: dealId, tenantId, deletedAt: null }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const deal = await findOneWithDecryption<CustomerDeal>(\n em,\n CustomerDeal,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!deal || deal.tenantId !== tenantId) return null\n if (ctx.organizationId && deal.organizationId !== ctx.organizationId) return null\n return deal\n}\n\n/**\n * `CustomerDeal` does NOT carry a direct `entity` field \u2014 deals are linked\n * to people / companies via the `customer_deal_person_links` and\n * `customer_deal_company_links` tables. Comments however need a non-null\n * `entity_id` (the timeline owner) so this helper resolves the deal's\n * first linked person, then falls back to its first linked company. When\n * neither exists, the caller MUST instruct the operator to link a contact\n * before commenting on the deal.\n */\nasync function resolveDealCommentEntityId(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n dealId: string,\n): Promise<string | null> {\n const personLink = await em.findOne(\n CustomerDealPersonLink,\n { deal: dealId, tenantId } as never,\n { populate: ['personEntity'] as never },\n )\n if (personLink) {\n const linked = (personLink as unknown as { personEntity?: { id?: string | null } | null }).personEntity\n if (linked && typeof linked === 'object' && typeof linked.id === 'string') return linked.id\n const raw = (personLink as unknown as { personEntity?: unknown }).personEntity\n if (typeof raw === 'string') return raw\n }\n const companyLink = await em.findOne(\n CustomerDealCompanyLink,\n { deal: dealId, tenantId } as never,\n { populate: ['companyEntity'] as never },\n )\n if (companyLink) {\n const linked = (companyLink as unknown as { companyEntity?: { id?: string | null } | null }).companyEntity\n if (linked && typeof linked === 'object' && typeof linked.id === 'string') return linked.id\n const raw = (companyLink as unknown as { companyEntity?: unknown }).companyEntity\n if (typeof raw === 'string') return raw\n }\n return null\n}\n\nasync function loadCommentForScope(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n commentId: string,\n): Promise<CustomerComment | null> {\n const where: Record<string, unknown> = { id: commentId, tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const row = await findOneWithDecryption<CustomerComment>(\n em,\n CustomerComment,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!row || row.tenantId !== tenantId) return null\n if (ctx.organizationId && row.organizationId !== ctx.organizationId) return null\n return row\n}\n\nasync function loadActivityForScope(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n activityId: string,\n): Promise<CustomerActivity | null> {\n const where: Record<string, unknown> = { id: activityId, tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const row = await findOneWithDecryption<CustomerActivity>(\n em,\n CustomerActivity,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!row || row.tenantId !== tenantId) return null\n if (ctx.organizationId && row.organizationId !== ctx.organizationId) return null\n return row\n}\n\nfunction commentEntityIdOf(row: CustomerComment): string | null {\n const ent = (row as any).entity\n if (!ent) return null\n if (typeof ent === 'string') return ent\n if (typeof ent === 'object' && typeof ent.id === 'string') return ent.id\n return null\n}\n\nfunction activityEntityIdOf(row: CustomerActivity): string | null {\n const ent = (row as any).entity\n if (!ent) return null\n if (typeof ent === 'string') return ent\n if (typeof ent === 'object' && typeof ent.id === 'string') return ent.id\n return null\n}\n\nconst listActivitiesInput = z\n .object({\n personId: z.string().uuid().optional().describe('Restrict to activities attached to this person entity id.'),\n companyId: z.string().uuid().optional().describe('Restrict to activities attached to this company entity id.'),\n dealId: z.string().uuid().optional().describe('Restrict to activities attached to this deal id.'),\n activityType: z.string().optional().describe('Filter by activity type (e.g. \"call\", \"email\").'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listActivitiesTool: CustomersAiToolDefinition = {\n name: 'customers.list_activities',\n displayName: 'List activities',\n description:\n 'List logged customer activities (calls, emails, meetings, notes, etc.) scoped to tenant + organization. Supply `personId` / `companyId` / `dealId` to narrow; otherwise returns the most recent activities across the tenant.',\n inputSchema: listActivitiesInput,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listActivitiesInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const entityId = input.personId ?? input.companyId ?? null\n if (entityId) where.entity = entityId\n if (input.dealId) where.deal = input.dealId\n if (input.activityType) where.activityType = input.activityType\n const [rows, total] = await Promise.all([\n findWithDecryption<CustomerActivity>(\n em,\n CustomerActivity,\n where as any,\n { limit, offset, orderBy: { occurredAt: 'desc', createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CustomerActivity, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n activityType: row.activityType,\n subject: row.subject ?? null,\n body: row.body ?? null,\n occurredAt: row.occurredAt ? new Date(row.occurredAt).toISOString() : null,\n authorUserId: row.authorUserId ?? null,\n entityId: activityEntityIdOf(row),\n dealId: (row as any).deal && typeof (row as any).deal === 'object' ? (row as any).deal.id : (row as any).deal ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\nconst listTasksInput = z\n .object({\n personId: z.string().uuid().optional().describe('Restrict to tasks linked to this person entity id.'),\n companyId: z.string().uuid().optional().describe('Restrict to tasks linked to this company entity id.'),\n dealId: z.string().uuid().optional().describe('Restrict to tasks connected to this deal id.'),\n status: z\n .enum(['open', 'done', 'cancelled'])\n .optional()\n .describe('Filter canonical interaction tasks by status. Ignored when listing legacy todo links.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listTasksTool: CustomersAiToolDefinition = {\n name: 'customers.list_tasks',\n displayName: 'List tasks',\n description:\n 'List customer tasks scoped to tenant + organization. Returns canonical interaction tasks (interactionType=\"task\") merged with legacy todo links for compatibility.',\n inputSchema: listTasksInput,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listTasksInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const entityId = input.personId ?? input.companyId ?? null\n const interactionWhere: Record<string, unknown> = {\n tenantId,\n interactionType: 'task',\n deletedAt: null,\n }\n if (ctx.organizationId) interactionWhere.organizationId = ctx.organizationId\n if (entityId) interactionWhere.entity = entityId\n if (input.dealId) interactionWhere.dealId = input.dealId\n if (input.status) interactionWhere.status = input.status === 'open' ? 'planned' : input.status === 'done' ? 'completed' : 'cancelled'\n const interactionRows = await findWithDecryption<CustomerInteraction>(\n em,\n CustomerInteraction,\n interactionWhere as any,\n { limit, offset, orderBy: { scheduledAt: 'desc', createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n )\n const legacyWhere: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) legacyWhere.organizationId = ctx.organizationId\n if (entityId) legacyWhere.entity = entityId\n const legacyRows =\n input.status || input.dealId\n ? []\n : await findWithDecryption<CustomerTodoLink>(\n em,\n CustomerTodoLink,\n legacyWhere as any,\n { limit, offset, orderBy: { createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n )\n const filteredInteractions = interactionRows.filter((row) => row.tenantId === tenantId)\n const filteredLegacy = legacyRows.filter((row) => row.tenantId === tenantId)\n const items = [\n ...filteredInteractions.map((row) => ({\n kind: 'interaction' as const,\n id: row.id,\n title: row.title ?? null,\n body: row.body ?? null,\n status: row.status,\n scheduledAt: row.scheduledAt ? new Date(row.scheduledAt).toISOString() : null,\n occurredAt: row.occurredAt ? new Date(row.occurredAt).toISOString() : null,\n dealId: row.dealId ?? null,\n ownerUserId: row.ownerUserId ?? null,\n priority: row.priority ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n ...filteredLegacy.map((row) => ({\n kind: 'todo_link' as const,\n id: row.id,\n todoId: row.todoId,\n todoSource: row.todoSource,\n entityId: (row as any).entity && typeof (row as any).entity === 'object' ? (row as any).entity.id : (row as any).entity ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n ]\n return {\n items,\n total: items.length,\n limit,\n offset,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.list_deal_comments \u2014 read-only dedicated comment listing\n// ---------------------------------------------------------------------------\n\nconst listDealCommentsInput = z\n .object({\n dealId: z.string().uuid().describe('Deal id whose comments should be listed.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listDealCommentsTool: CustomersAiToolDefinition = {\n name: 'customers.list_deal_comments',\n displayName: 'List deal comments',\n description:\n 'List comments left on a specific deal, ordered by most recent first. Read-only; tenant + organization scoped.',\n inputSchema: listDealCommentsInput,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listDealCommentsInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId, deal: input.dealId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const [rows, total] = await Promise.all([\n findWithDecryption<CustomerComment>(\n em,\n CustomerComment,\n where as any,\n { limit, offset, orderBy: { createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CustomerComment, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n body: row.body ?? null,\n entityId: commentEntityIdOf(row),\n dealId: (row as any).deal && typeof (row as any).deal === 'object' ? (row as any).deal.id : (row as any).deal ?? null,\n authorUserId: row.authorUserId ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_deal_comment \u2014 create / update / delete a deal comment\n// ---------------------------------------------------------------------------\n\nconst manageDealCommentInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new comment, update an existing one, or delete it.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` \u2014 the deal the comment is attached to.'),\n commentId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete` \u2014 id of the existing comment row.'),\n body: z\n .preprocess(blankToUndefined, z.string().min(1).max(8000).optional())\n .describe('Comment text. Required for `create`; optional on `update`.'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.dealId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'dealId is required for create.', path: ['dealId'] })\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for create.', path: ['body'] })\n }\n if (value.operation === 'update') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for update.', path: ['commentId'] })\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for update.', path: ['body'] })\n }\n if (value.operation === 'delete') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for delete.', path: ['commentId'] })\n }\n })\n\ntype ManageDealCommentInput = z.infer<typeof manageDealCommentInput>\n\nconst manageDealCommentTool: CustomersAiToolDefinition = {\n name: 'customers.manage_deal_comment',\n displayName: 'Manage deal comment',\n description:\n 'Create, update, or delete a comment on a deal. Use `operation` to pick the action. Under `destructive-confirm-required` policy, only the `delete` branch routes through the approval card; `create` and `update` execute directly.',\n inputSchema: manageDealCommentInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n // Predicate `isDestructive`: only the `delete` branch counts as\n // destructive. Under `confirm-required` policy every branch still\n // gates (the framework ignores this flag); under\n // `destructive-confirm-required` only deletes go through the approval\n // card while creates/updates run directly.\n isDestructive: (input: unknown) => {\n if (!input || typeof input !== 'object') return false\n return (input as { operation?: unknown }).operation === 'delete'\n },\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealCommentInput = manageDealCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { commentId: null, body: null, dealId: deal.id },\n }\n }\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_comment',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n body: existing.body ?? null,\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n entityId: commentEntityIdOf(existing),\n authorUserId: existing.authorUserId ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealCommentInput = manageDealCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n const organizationId = deal.organizationId\n if (!organizationId) throw new Error(`Deal \"${deal.id}\" has no organization scope.`)\n // `CustomerDeal` has no direct `.entity` field \u2014 deals link to\n // people/companies via two link tables. Resolve the first available\n // person, then fall back to the first linked company. Only fail the\n // operation when the deal has no linked contacts at all.\n const dealEntityId = await resolveDealCommentEntityId(em, ctx, tenantId, deal.id)\n if (!dealEntityId) {\n throw new Error(\n `Deal \"${deal.id}\" has no linked person or company. Link a contact to the deal in the backoffice before adding a comment, or post the comment directly on the person/company record instead.`,\n )\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n dealId: deal.id,\n // Comments require an `entityId` (the person/company on the timeline).\n entityId: dealEntityId,\n body: input.body,\n }\n const response = await runner.run({ method: 'POST', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create comment')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n commentId: result.id ?? null,\n dealId: deal.id,\n commandName: 'customers.comments.create',\n before: null,\n after: { body: input.body ?? null, dealId: deal.id },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Comment \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = {\n id: existing.id,\n tenantId,\n organizationId,\n body: input.body,\n }\n const response = await runner.run({ method: 'PUT', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update comment \"${existing.id}\"`)\n }\n const after = await loadCommentForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n commentId: existing.id,\n commandName: 'customers.comments.update',\n before: { body: existing.body ?? null },\n after: after ? { body: after.body ?? null } : null,\n }\n }\n\n // delete\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete comment \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n commentId: existing.id,\n commandName: 'customers.comments.delete',\n before: { body: existing.body ?? null },\n after: null,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_deal_activity \u2014 create / update / delete an activity\n// ---------------------------------------------------------------------------\n\nconst manageDealActivityInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new activity, update an existing one, or delete it.'),\n activityId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete`.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` \u2014 the deal the activity is logged against.'),\n activityType: z\n .preprocess(blankToUndefined, z.string().min(1).max(100).optional())\n .describe('Required for `create` \u2014 e.g. \"call\", \"email\", \"meeting\", \"note\".'),\n subject: z\n .preprocess(blankToUndefined, z.string().max(200).optional())\n .describe('Optional short subject line.'),\n body: z\n .preprocess(blankToUndefined, z.string().max(8000).optional())\n .describe('Optional free-text body.'),\n occurredAt: z\n .preprocess(blankToUndefined, z.string().datetime().optional())\n .describe('ISO-8601 timestamp when the activity occurred. Omit for \"now\" (server-side default applies).'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.dealId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'dealId is required for create.', path: ['dealId'] })\n if (!value.activityType) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityType is required for create.', path: ['activityType'] })\n }\n if (value.operation === 'update' || value.operation === 'delete') {\n if (!value.activityId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityId is required.', path: ['activityId'] })\n }\n })\n\ntype ManageDealActivityInput = z.infer<typeof manageDealActivityInput>\n\nconst manageDealActivityTool: CustomersAiToolDefinition = {\n name: 'customers.manage_deal_activity',\n displayName: 'Manage deal activity',\n description:\n 'Create, update, or delete a deal activity (call, email, meeting, note, etc.). Mutation tool \u2014 every call routes through the AI pending-action approval gate. Use `operation` to pick the action.',\n inputSchema: manageDealActivityInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealActivityInput = manageDealActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { activityId: null, dealId: deal.id },\n }\n }\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_activity',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealActivityInput = manageDealActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n const organizationId = deal.organizationId\n if (!organizationId) throw new Error(`Deal \"${deal.id}\" has no organization scope.`)\n const dealEntity = (deal as unknown as { entity?: unknown }).entity\n const entityId =\n dealEntity && typeof dealEntity === 'object'\n ? (dealEntity as { id?: string | null }).id ?? null\n : typeof dealEntity === 'string'\n ? dealEntity\n : null\n if (!entityId) {\n throw new Error(`Deal \"${deal.id}\" has no associated person/company; cannot attach an activity.`)\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n entityId,\n dealId: deal.id,\n activityType: input.activityType,\n }\n if (input.subject) body.subject = input.subject\n if (input.body) body.body = input.body\n if (input.occurredAt) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'POST', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create activity')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n activityId: result.id ?? null,\n dealId: deal.id,\n commandName: 'customers.activities.create',\n before: null,\n after: {\n activityType: input.activityType ?? null,\n subject: input.subject ?? null,\n body: input.body ?? null,\n occurredAt: input.occurredAt ?? null,\n },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Activity \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = { id: existing.id, tenantId, organizationId }\n if (input.activityType) body.activityType = input.activityType\n if (input.subject !== undefined) body.subject = input.subject\n if (input.body !== undefined) body.body = input.body\n if (input.occurredAt !== undefined) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'PUT', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update activity \"${existing.id}\"`)\n }\n const after = await loadActivityForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n activityId: existing.id,\n commandName: 'customers.activities.update',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n },\n after: after\n ? {\n activityType: after.activityType,\n subject: after.subject ?? null,\n body: after.body ?? null,\n occurredAt: after.occurredAt ? new Date(after.occurredAt).toISOString() : null,\n }\n : null,\n }\n }\n\n // delete\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete activity \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n activityId: existing.id,\n commandName: 'customers.activities.delete',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n },\n after: null,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.list_record_comments \u2014 list comments on a person / company / deal\n// ---------------------------------------------------------------------------\n\nconst listRecordCommentsInput = z\n .object({\n personId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Restrict to comments on this person entity id.'),\n companyId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Restrict to comments on this company entity id.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Restrict to comments attached to this deal id.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .superRefine((value, ctx) => {\n if (!value.personId && !value.companyId && !value.dealId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide at least one of personId, companyId, or dealId.',\n path: ['personId'],\n })\n }\n })\n\nconst listRecordCommentsTool: CustomersAiToolDefinition = {\n name: 'customers.list_record_comments',\n displayName: 'List record comments',\n description:\n 'List comments left on a person, company, or deal record. Read-only; tenant + organization scoped. Provide at least one of `personId`, `companyId`, or `dealId`.',\n inputSchema: listRecordCommentsInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listRecordCommentsInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const entityId = input.personId ?? input.companyId ?? null\n if (entityId) where.entity = entityId\n if (input.dealId) where.deal = input.dealId\n const [rows, total] = await Promise.all([\n findWithDecryption<CustomerComment>(\n em,\n CustomerComment,\n where as any,\n { limit, offset, orderBy: { createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CustomerComment, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n body: row.body ?? null,\n entityId: commentEntityIdOf(row),\n dealId: (row as any).deal && typeof (row as any).deal === 'object' ? (row as any).deal.id : (row as any).deal ?? null,\n authorUserId: row.authorUserId ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_record_comment \u2014 create / update / delete a comment on a\n// person, company, or deal record. Mutation tool.\n// ---------------------------------------------------------------------------\n\nconst manageRecordCommentInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new comment, update an existing one, or delete it.'),\n personId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `companyId`) \u2014 the person entity the comment is attached to.'),\n companyId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `personId`) \u2014 the company entity the comment is attached to.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Optional on `create` \u2014 when set, the comment also shows up under that deal.'),\n commentId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete` \u2014 id of the existing comment row.'),\n body: z\n .preprocess(blankToUndefined, z.string().min(1).max(8000).optional())\n .describe('Comment text. Required for `create`; optional on `update`.'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.personId && !value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide personId or companyId for create.',\n path: ['personId'],\n })\n }\n if (value.personId && value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide only one of personId or companyId.',\n path: ['personId'],\n })\n }\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for create.', path: ['body'] })\n }\n if (value.operation === 'update') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for update.', path: ['commentId'] })\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for update.', path: ['body'] })\n }\n if (value.operation === 'delete') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for delete.', path: ['commentId'] })\n }\n })\n\ntype ManageRecordCommentInput = z.infer<typeof manageRecordCommentInput>\n\nconst manageRecordCommentTool: CustomersAiToolDefinition = {\n name: 'customers.manage_record_comment',\n displayName: 'Manage record comment',\n description:\n 'Create, update, or delete a comment on a person, company, or deal record. Mutation tool \u2014 every call routes through the AI pending-action approval gate. Use `operation` to pick the action; for `create` provide `personId` OR `companyId` (and optionally `dealId`).',\n inputSchema: manageRecordCommentInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordCommentInput = manageRecordCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId\n // We do not load the host person/company entity here \u2014 the\n // `customers/comments` POST handler validates its existence and tenant\n // scope. We do hydrate the deal when supplied so the approval card has\n // a stable record-version anchor.\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { commentId: null, body: null, entityId, dealId: deal.id },\n }\n }\n return {\n recordId: entityId!,\n entityType: input.personId ? 'customers.person' : 'customers.company',\n recordVersion: null,\n before: { commentId: null, body: null, entityId, dealId: null },\n }\n }\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_comment',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n body: existing.body ?? null,\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n entityId: commentEntityIdOf(existing),\n authorUserId: existing.authorUserId ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordCommentInput = manageRecordCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId!\n // Resolve organization scope: prefer the deal's org when one is supplied,\n // otherwise fall back to the caller context's org.\n let organizationId: string | null = ctx.organizationId\n let dealId: string | null = null\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n organizationId = deal.organizationId ?? organizationId\n dealId = deal.id\n }\n if (!organizationId) {\n throw new Error('Organization scope is required to create a comment.')\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n entityId,\n body: input.body,\n }\n if (dealId) body.dealId = dealId\n const response = await runner.run({ method: 'POST', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create comment')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n commentId: result.id ?? null,\n entityId,\n dealId,\n commandName: 'customers.comments.create',\n before: null,\n after: { body: input.body ?? null, entityId, dealId },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Comment \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = {\n id: existing.id,\n tenantId,\n organizationId,\n body: input.body,\n }\n const response = await runner.run({ method: 'PUT', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update comment \"${existing.id}\"`)\n }\n const after = await loadCommentForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n commentId: existing.id,\n commandName: 'customers.comments.update',\n before: { body: existing.body ?? null },\n after: after ? { body: after.body ?? null } : null,\n }\n }\n\n // delete\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete comment \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n commentId: existing.id,\n commandName: 'customers.comments.delete',\n before: { body: existing.body ?? null },\n after: null,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_record_activity \u2014 create / update / delete an activity on\n// a person, company, or deal record. Mutation tool.\n// ---------------------------------------------------------------------------\n\nconst manageRecordActivityInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new activity, update an existing one, or delete it.'),\n activityId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete`.'),\n personId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `companyId`) \u2014 the person entity the activity is logged on.'),\n companyId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `personId`) \u2014 the company entity the activity is logged on.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Optional on `create` \u2014 when set, the activity is also linked to that deal.'),\n activityType: z\n .preprocess(blankToUndefined, z.string().min(1).max(100).optional())\n .describe('Required for `create` \u2014 e.g. \"call\", \"email\", \"meeting\", \"note\".'),\n subject: z\n .preprocess(blankToUndefined, z.string().max(200).optional())\n .describe('Optional short subject line.'),\n body: z\n .preprocess(blankToUndefined, z.string().max(8000).optional())\n .describe('Optional free-text body.'),\n occurredAt: z\n .preprocess(blankToUndefined, z.string().datetime().optional())\n .describe('ISO-8601 timestamp when the activity occurred. Omit for \"now\" (server-side default applies).'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.personId && !value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide personId or companyId for create.',\n path: ['personId'],\n })\n }\n if (value.personId && value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide only one of personId or companyId.',\n path: ['personId'],\n })\n }\n if (!value.activityType) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityType is required for create.', path: ['activityType'] })\n }\n if (value.operation === 'update' || value.operation === 'delete') {\n if (!value.activityId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityId is required.', path: ['activityId'] })\n }\n })\n\ntype ManageRecordActivityInput = z.infer<typeof manageRecordActivityInput>\n\nconst manageRecordActivityTool: CustomersAiToolDefinition = {\n name: 'customers.manage_record_activity',\n displayName: 'Manage record activity',\n description:\n 'Create, update, or delete an activity (call, email, meeting, note) on a person, company, or deal record. Mutation tool \u2014 every call routes through the AI pending-action approval gate. For `create` provide `personId` OR `companyId` (and optionally `dealId`).',\n inputSchema: manageRecordActivityInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordActivityInput = manageRecordActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { activityId: null, dealId: deal.id, entityId },\n }\n }\n return {\n recordId: entityId!,\n entityType: input.personId ? 'customers.person' : 'customers.company',\n recordVersion: null,\n before: { activityId: null, entityId, dealId: null },\n }\n }\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_activity',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n entityId: activityEntityIdOf(existing),\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordActivityInput = manageRecordActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId!\n let organizationId: string | null = ctx.organizationId\n let dealId: string | null = null\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n organizationId = deal.organizationId ?? organizationId\n dealId = deal.id\n }\n if (!organizationId) {\n throw new Error('Organization scope is required to create an activity.')\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n entityId,\n activityType: input.activityType,\n }\n if (dealId) body.dealId = dealId\n if (input.subject) body.subject = input.subject\n if (input.body) body.body = input.body\n if (input.occurredAt) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'POST', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create activity')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n activityId: result.id ?? null,\n entityId,\n dealId,\n commandName: 'customers.activities.create',\n before: null,\n after: {\n activityType: input.activityType ?? null,\n subject: input.subject ?? null,\n body: input.body ?? null,\n occurredAt: input.occurredAt ?? null,\n },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Activity \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = { id: existing.id, tenantId, organizationId }\n if (input.activityType) body.activityType = input.activityType\n if (input.subject !== undefined) body.subject = input.subject\n if (input.body !== undefined) body.body = input.body\n if (input.occurredAt !== undefined) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'PUT', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update activity \"${existing.id}\"`)\n }\n const after = await loadActivityForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n activityId: existing.id,\n commandName: 'customers.activities.update',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n },\n after: after\n ? {\n activityType: after.activityType,\n subject: after.subject ?? null,\n body: after.body ?? null,\n occurredAt: after.occurredAt ? new Date(after.occurredAt).toISOString() : null,\n }\n : null,\n }\n }\n\n // delete\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete activity \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n activityId: existing.id,\n commandName: 'customers.activities.delete',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n },\n after: null,\n }\n },\n}\n\nexport const activitiesTasksAiTools: CustomersAiToolDefinition[] = [\n listActivitiesTool,\n listTasksTool,\n listDealCommentsTool,\n manageDealCommentTool,\n manageDealActivityTool,\n listRecordCommentsTool,\n manageRecordCommentTool,\n manageRecordActivityTool,\n]\n\nexport default activitiesTasksAiTools\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * `customers.list_activities` + `customers.list_tasks` (Phase 1 WS-C, Step 3.9)\n * plus the deal comment / activity manage tools (Phase 3 WS-C, follow-up).\n *\n * The mutation tools route every write through the AI pending-action approval\n * gate via `createAiApiOperationRunner` \u2014 same contract as\n * `customers.update_deal_stage`.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport {\n createAiApiOperationRunner,\n type AiToolExecutionContext,\n} from '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { TERMINAL_INTERACTION_STATUS_LIST } from '../lib/interactionStatus'\nimport {\n CustomerActivity,\n CustomerComment,\n CustomerDeal,\n CustomerDealCompanyLink,\n CustomerDealPersonLink,\n CustomerInteraction,\n CustomerTodoLink,\n} from '../data/entities'\nimport {\n assertTenantScope,\n type CustomersAiToolDefinition,\n type CustomersToolContext,\n type CustomersToolLoadBeforeSingleRecord,\n} from './types'\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 { tenantId, organizationId: ctx.organizationId }\n}\n\nfunction recordVersionFromUpdatedAt(updatedAt: Date | null | undefined): string | null {\n if (!updatedAt) return null\n const value = updatedAt instanceof Date ? updatedAt : new Date(updatedAt)\n if (Number.isNaN(value.getTime())) return null\n return value.toISOString()\n}\n\n// LLMs frequently emit `\"\"` for \"not provided\" \u2014 coerce blanks (and surrounding\n// whitespace) to `undefined` BEFORE per-field validators run. Mirrors the\n// `blankToUndefined` helper in deals-pack.ts.\nconst blankToUndefined = (value: unknown): unknown => {\n if (typeof value !== 'string') return value\n const trimmed = value.trim()\n return trimmed.length === 0 ? undefined : trimmed\n}\n\nasync function loadDealForScope(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n dealId: string,\n): Promise<CustomerDeal | null> {\n const where: Record<string, unknown> = { id: dealId, tenantId, deletedAt: null }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const deal = await findOneWithDecryption<CustomerDeal>(\n em,\n CustomerDeal,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!deal || deal.tenantId !== tenantId) return null\n if (ctx.organizationId && deal.organizationId !== ctx.organizationId) return null\n return deal\n}\n\n/**\n * `CustomerDeal` does NOT carry a direct `entity` field \u2014 deals are linked\n * to people / companies via the `customer_deal_person_links` and\n * `customer_deal_company_links` tables. Comments however need a non-null\n * `entity_id` (the timeline owner) so this helper resolves the deal's\n * first linked person, then falls back to its first linked company. When\n * neither exists, the caller MUST instruct the operator to link a contact\n * before commenting on the deal.\n */\nasync function resolveDealCommentEntityId(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n dealId: string,\n): Promise<string | null> {\n const personLink = await em.findOne(\n CustomerDealPersonLink,\n { deal: dealId, tenantId } as never,\n { populate: ['personEntity'] as never },\n )\n if (personLink) {\n const linked = (personLink as unknown as { personEntity?: { id?: string | null } | null }).personEntity\n if (linked && typeof linked === 'object' && typeof linked.id === 'string') return linked.id\n const raw = (personLink as unknown as { personEntity?: unknown }).personEntity\n if (typeof raw === 'string') return raw\n }\n const companyLink = await em.findOne(\n CustomerDealCompanyLink,\n { deal: dealId, tenantId } as never,\n { populate: ['companyEntity'] as never },\n )\n if (companyLink) {\n const linked = (companyLink as unknown as { companyEntity?: { id?: string | null } | null }).companyEntity\n if (linked && typeof linked === 'object' && typeof linked.id === 'string') return linked.id\n const raw = (companyLink as unknown as { companyEntity?: unknown }).companyEntity\n if (typeof raw === 'string') return raw\n }\n return null\n}\n\nasync function loadCommentForScope(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n commentId: string,\n): Promise<CustomerComment | null> {\n const where: Record<string, unknown> = { id: commentId, tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const row = await findOneWithDecryption<CustomerComment>(\n em,\n CustomerComment,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!row || row.tenantId !== tenantId) return null\n if (ctx.organizationId && row.organizationId !== ctx.organizationId) return null\n return row\n}\n\nasync function loadActivityForScope(\n em: EntityManager,\n ctx: CustomersToolContext,\n tenantId: string,\n activityId: string,\n): Promise<CustomerActivity | null> {\n const where: Record<string, unknown> = { id: activityId, tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const row = await findOneWithDecryption<CustomerActivity>(\n em,\n CustomerActivity,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!row || row.tenantId !== tenantId) return null\n if (ctx.organizationId && row.organizationId !== ctx.organizationId) return null\n return row\n}\n\nfunction commentEntityIdOf(row: CustomerComment): string | null {\n const ent = (row as any).entity\n if (!ent) return null\n if (typeof ent === 'string') return ent\n if (typeof ent === 'object' && typeof ent.id === 'string') return ent.id\n return null\n}\n\nfunction activityEntityIdOf(row: CustomerActivity): string | null {\n const ent = (row as any).entity\n if (!ent) return null\n if (typeof ent === 'string') return ent\n if (typeof ent === 'object' && typeof ent.id === 'string') return ent.id\n return null\n}\n\nconst listActivitiesInput = z\n .object({\n personId: z.string().uuid().optional().describe('Restrict to activities attached to this person entity id.'),\n companyId: z.string().uuid().optional().describe('Restrict to activities attached to this company entity id.'),\n dealId: z.string().uuid().optional().describe('Restrict to activities attached to this deal id.'),\n activityType: z.string().optional().describe('Filter by activity type (e.g. \"call\", \"email\").'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listActivitiesTool: CustomersAiToolDefinition = {\n name: 'customers.list_activities',\n displayName: 'List activities',\n description:\n 'List logged customer activities (calls, emails, meetings, notes, etc.) scoped to tenant + organization. Supply `personId` / `companyId` / `dealId` to narrow; otherwise returns the most recent activities across the tenant.',\n inputSchema: listActivitiesInput,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listActivitiesInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const entityId = input.personId ?? input.companyId ?? null\n if (entityId) where.entity = entityId\n if (input.dealId) where.deal = input.dealId\n if (input.activityType) where.activityType = input.activityType\n const [rows, total] = await Promise.all([\n findWithDecryption<CustomerActivity>(\n em,\n CustomerActivity,\n where as any,\n { limit, offset, orderBy: { occurredAt: 'desc', createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CustomerActivity, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n activityType: row.activityType,\n subject: row.subject ?? null,\n body: row.body ?? null,\n occurredAt: row.occurredAt ? new Date(row.occurredAt).toISOString() : null,\n authorUserId: row.authorUserId ?? null,\n entityId: activityEntityIdOf(row),\n dealId: (row as any).deal && typeof (row as any).deal === 'object' ? (row as any).deal.id : (row as any).deal ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\nconst listTasksInput = z\n .object({\n personId: z.string().uuid().optional().describe('Restrict to tasks linked to this person entity id.'),\n companyId: z.string().uuid().optional().describe('Restrict to tasks linked to this company entity id.'),\n dealId: z.string().uuid().optional().describe('Restrict to tasks connected to this deal id.'),\n status: z\n .enum(['open', 'in_progress', 'waiting', 'done', 'canceled', 'cancelled'])\n .optional()\n .describe('Filter canonical interaction tasks by status. \"open\" matches every non-terminal status (planned/in_progress/waiting and custom statuses). \"cancelled\" is accepted as an alias for \"canceled\". Ignored when listing legacy todo links.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listTasksTool: CustomersAiToolDefinition = {\n name: 'customers.list_tasks',\n displayName: 'List tasks',\n description:\n 'List customer tasks scoped to tenant + organization. Returns canonical interaction tasks (interactionType=\"task\") merged with legacy todo links for compatibility.',\n inputSchema: listTasksInput,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listTasksInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const entityId = input.personId ?? input.companyId ?? null\n const interactionWhere: Record<string, unknown> = {\n tenantId,\n interactionType: 'task',\n deletedAt: null,\n }\n if (ctx.organizationId) interactionWhere.organizationId = ctx.organizationId\n if (entityId) interactionWhere.entity = entityId\n if (input.dealId) interactionWhere.dealId = input.dealId\n if (input.status) {\n if (input.status === 'open') {\n interactionWhere.status = { $nin: [...TERMINAL_INTERACTION_STATUS_LIST] }\n } else if (input.status === 'cancelled') {\n interactionWhere.status = 'canceled'\n } else {\n interactionWhere.status = input.status\n }\n }\n const interactionRows = await findWithDecryption<CustomerInteraction>(\n em,\n CustomerInteraction,\n interactionWhere as any,\n { limit, offset, orderBy: { scheduledAt: 'desc', createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n )\n const legacyWhere: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) legacyWhere.organizationId = ctx.organizationId\n if (entityId) legacyWhere.entity = entityId\n const legacyRows =\n input.status || input.dealId\n ? []\n : await findWithDecryption<CustomerTodoLink>(\n em,\n CustomerTodoLink,\n legacyWhere as any,\n { limit, offset, orderBy: { createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n )\n const filteredInteractions = interactionRows.filter((row) => row.tenantId === tenantId)\n const filteredLegacy = legacyRows.filter((row) => row.tenantId === tenantId)\n const items = [\n ...filteredInteractions.map((row) => ({\n kind: 'interaction' as const,\n id: row.id,\n title: row.title ?? null,\n body: row.body ?? null,\n status: row.status,\n scheduledAt: row.scheduledAt ? new Date(row.scheduledAt).toISOString() : null,\n occurredAt: row.occurredAt ? new Date(row.occurredAt).toISOString() : null,\n dealId: row.dealId ?? null,\n ownerUserId: row.ownerUserId ?? null,\n priority: row.priority ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n ...filteredLegacy.map((row) => ({\n kind: 'todo_link' as const,\n id: row.id,\n todoId: row.todoId,\n todoSource: row.todoSource,\n entityId: (row as any).entity && typeof (row as any).entity === 'object' ? (row as any).entity.id : (row as any).entity ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n ]\n return {\n items,\n total: items.length,\n limit,\n offset,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.list_deal_comments \u2014 read-only dedicated comment listing\n// ---------------------------------------------------------------------------\n\nconst listDealCommentsInput = z\n .object({\n dealId: z.string().uuid().describe('Deal id whose comments should be listed.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listDealCommentsTool: CustomersAiToolDefinition = {\n name: 'customers.list_deal_comments',\n displayName: 'List deal comments',\n description:\n 'List comments left on a specific deal, ordered by most recent first. Read-only; tenant + organization scoped.',\n inputSchema: listDealCommentsInput,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listDealCommentsInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId, deal: input.dealId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const [rows, total] = await Promise.all([\n findWithDecryption<CustomerComment>(\n em,\n CustomerComment,\n where as any,\n { limit, offset, orderBy: { createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CustomerComment, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n body: row.body ?? null,\n entityId: commentEntityIdOf(row),\n dealId: (row as any).deal && typeof (row as any).deal === 'object' ? (row as any).deal.id : (row as any).deal ?? null,\n authorUserId: row.authorUserId ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_deal_comment \u2014 create / update / delete a deal comment\n// ---------------------------------------------------------------------------\n\nconst manageDealCommentInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new comment, update an existing one, or delete it.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` \u2014 the deal the comment is attached to.'),\n commentId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete` \u2014 id of the existing comment row.'),\n body: z\n .preprocess(blankToUndefined, z.string().min(1).max(8000).optional())\n .describe('Comment text. Required for `create`; optional on `update`.'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.dealId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'dealId is required for create.', path: ['dealId'] })\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for create.', path: ['body'] })\n }\n if (value.operation === 'update') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for update.', path: ['commentId'] })\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for update.', path: ['body'] })\n }\n if (value.operation === 'delete') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for delete.', path: ['commentId'] })\n }\n })\n\ntype ManageDealCommentInput = z.infer<typeof manageDealCommentInput>\n\nconst manageDealCommentTool: CustomersAiToolDefinition = {\n name: 'customers.manage_deal_comment',\n displayName: 'Manage deal comment',\n description:\n 'Create, update, or delete a comment on a deal. Use `operation` to pick the action. Under `destructive-confirm-required` policy, only the `delete` branch routes through the approval card; `create` and `update` execute directly.',\n inputSchema: manageDealCommentInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n // Predicate `isDestructive`: only the `delete` branch counts as\n // destructive. Under `confirm-required` policy every branch still\n // gates (the framework ignores this flag); under\n // `destructive-confirm-required` only deletes go through the approval\n // card while creates/updates run directly.\n isDestructive: (input: unknown) => {\n if (!input || typeof input !== 'object') return false\n return (input as { operation?: unknown }).operation === 'delete'\n },\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealCommentInput = manageDealCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { commentId: null, body: null, dealId: deal.id },\n }\n }\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_comment',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n body: existing.body ?? null,\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n entityId: commentEntityIdOf(existing),\n authorUserId: existing.authorUserId ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealCommentInput = manageDealCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n const organizationId = deal.organizationId\n if (!organizationId) throw new Error(`Deal \"${deal.id}\" has no organization scope.`)\n // `CustomerDeal` has no direct `.entity` field \u2014 deals link to\n // people/companies via two link tables. Resolve the first available\n // person, then fall back to the first linked company. Only fail the\n // operation when the deal has no linked contacts at all.\n const dealEntityId = await resolveDealCommentEntityId(em, ctx, tenantId, deal.id)\n if (!dealEntityId) {\n throw new Error(\n `Deal \"${deal.id}\" has no linked person or company. Link a contact to the deal in the backoffice before adding a comment, or post the comment directly on the person/company record instead.`,\n )\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n dealId: deal.id,\n // Comments require an `entityId` (the person/company on the timeline).\n entityId: dealEntityId,\n body: input.body,\n }\n const response = await runner.run({ method: 'POST', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create comment')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n commentId: result.id ?? null,\n dealId: deal.id,\n commandName: 'customers.comments.create',\n before: null,\n after: { body: input.body ?? null, dealId: deal.id },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Comment \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = {\n id: existing.id,\n tenantId,\n organizationId,\n body: input.body,\n }\n const response = await runner.run({ method: 'PUT', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update comment \"${existing.id}\"`)\n }\n const after = await loadCommentForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n commentId: existing.id,\n commandName: 'customers.comments.update',\n before: { body: existing.body ?? null },\n after: after ? { body: after.body ?? null } : null,\n }\n }\n\n // delete\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete comment \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n commentId: existing.id,\n commandName: 'customers.comments.delete',\n before: { body: existing.body ?? null },\n after: null,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_deal_activity \u2014 create / update / delete an activity\n// ---------------------------------------------------------------------------\n\nconst manageDealActivityInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new activity, update an existing one, or delete it.'),\n activityId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete`.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` \u2014 the deal the activity is logged against.'),\n activityType: z\n .preprocess(blankToUndefined, z.string().min(1).max(100).optional())\n .describe('Required for `create` \u2014 e.g. \"call\", \"email\", \"meeting\", \"note\".'),\n subject: z\n .preprocess(blankToUndefined, z.string().max(200).optional())\n .describe('Optional short subject line.'),\n body: z\n .preprocess(blankToUndefined, z.string().max(8000).optional())\n .describe('Optional free-text body.'),\n occurredAt: z\n .preprocess(blankToUndefined, z.string().datetime().optional())\n .describe('ISO-8601 timestamp when the activity occurred. Omit for \"now\" (server-side default applies).'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.dealId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'dealId is required for create.', path: ['dealId'] })\n if (!value.activityType) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityType is required for create.', path: ['activityType'] })\n }\n if (value.operation === 'update' || value.operation === 'delete') {\n if (!value.activityId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityId is required.', path: ['activityId'] })\n }\n })\n\ntype ManageDealActivityInput = z.infer<typeof manageDealActivityInput>\n\nconst manageDealActivityTool: CustomersAiToolDefinition = {\n name: 'customers.manage_deal_activity',\n displayName: 'Manage deal activity',\n description:\n 'Create, update, or delete a deal activity (call, email, meeting, note, etc.). Mutation tool \u2014 every call routes through the AI pending-action approval gate. Use `operation` to pick the action.',\n inputSchema: manageDealActivityInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealActivityInput = manageDealActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { activityId: null, dealId: deal.id },\n }\n }\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_activity',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageDealActivityInput = manageDealActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId!)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n const organizationId = deal.organizationId\n if (!organizationId) throw new Error(`Deal \"${deal.id}\" has no organization scope.`)\n const dealEntity = (deal as unknown as { entity?: unknown }).entity\n const entityId =\n dealEntity && typeof dealEntity === 'object'\n ? (dealEntity as { id?: string | null }).id ?? null\n : typeof dealEntity === 'string'\n ? dealEntity\n : null\n if (!entityId) {\n throw new Error(`Deal \"${deal.id}\" has no associated person/company; cannot attach an activity.`)\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n entityId,\n dealId: deal.id,\n activityType: input.activityType,\n }\n if (input.subject) body.subject = input.subject\n if (input.body) body.body = input.body\n if (input.occurredAt) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'POST', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create activity')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n activityId: result.id ?? null,\n dealId: deal.id,\n commandName: 'customers.activities.create',\n before: null,\n after: {\n activityType: input.activityType ?? null,\n subject: input.subject ?? null,\n body: input.body ?? null,\n occurredAt: input.occurredAt ?? null,\n },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Activity \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = { id: existing.id, tenantId, organizationId }\n if (input.activityType) body.activityType = input.activityType\n if (input.subject !== undefined) body.subject = input.subject\n if (input.body !== undefined) body.body = input.body\n if (input.occurredAt !== undefined) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'PUT', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update activity \"${existing.id}\"`)\n }\n const after = await loadActivityForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n activityId: existing.id,\n commandName: 'customers.activities.update',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n },\n after: after\n ? {\n activityType: after.activityType,\n subject: after.subject ?? null,\n body: after.body ?? null,\n occurredAt: after.occurredAt ? new Date(after.occurredAt).toISOString() : null,\n }\n : null,\n }\n }\n\n // delete\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete activity \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n activityId: existing.id,\n commandName: 'customers.activities.delete',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n },\n after: null,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.list_record_comments \u2014 list comments on a person / company / deal\n// ---------------------------------------------------------------------------\n\nconst listRecordCommentsInput = z\n .object({\n personId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Restrict to comments on this person entity id.'),\n companyId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Restrict to comments on this company entity id.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Restrict to comments attached to this deal id.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .superRefine((value, ctx) => {\n if (!value.personId && !value.companyId && !value.dealId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide at least one of personId, companyId, or dealId.',\n path: ['personId'],\n })\n }\n })\n\nconst listRecordCommentsTool: CustomersAiToolDefinition = {\n name: 'customers.list_record_comments',\n displayName: 'List record comments',\n description:\n 'List comments left on a person, company, or deal record. Read-only; tenant + organization scoped. Provide at least one of `personId`, `companyId`, or `dealId`.',\n inputSchema: listRecordCommentsInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.view'],\n tags: ['read', 'customers'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listRecordCommentsInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const entityId = input.personId ?? input.companyId ?? null\n if (entityId) where.entity = entityId\n if (input.dealId) where.deal = input.dealId\n const [rows, total] = await Promise.all([\n findWithDecryption<CustomerComment>(\n em,\n CustomerComment,\n where as any,\n { limit, offset, orderBy: { createdAt: 'desc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CustomerComment, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n body: row.body ?? null,\n entityId: commentEntityIdOf(row),\n dealId: (row as any).deal && typeof (row as any).deal === 'object' ? (row as any).deal.id : (row as any).deal ?? null,\n authorUserId: row.authorUserId ?? null,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_record_comment \u2014 create / update / delete a comment on a\n// person, company, or deal record. Mutation tool.\n// ---------------------------------------------------------------------------\n\nconst manageRecordCommentInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new comment, update an existing one, or delete it.'),\n personId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `companyId`) \u2014 the person entity the comment is attached to.'),\n companyId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `personId`) \u2014 the company entity the comment is attached to.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Optional on `create` \u2014 when set, the comment also shows up under that deal.'),\n commentId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete` \u2014 id of the existing comment row.'),\n body: z\n .preprocess(blankToUndefined, z.string().min(1).max(8000).optional())\n .describe('Comment text. Required for `create`; optional on `update`.'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.personId && !value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide personId or companyId for create.',\n path: ['personId'],\n })\n }\n if (value.personId && value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide only one of personId or companyId.',\n path: ['personId'],\n })\n }\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for create.', path: ['body'] })\n }\n if (value.operation === 'update') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for update.', path: ['commentId'] })\n if (!value.body) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'body is required for update.', path: ['body'] })\n }\n if (value.operation === 'delete') {\n if (!value.commentId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'commentId is required for delete.', path: ['commentId'] })\n }\n })\n\ntype ManageRecordCommentInput = z.infer<typeof manageRecordCommentInput>\n\nconst manageRecordCommentTool: CustomersAiToolDefinition = {\n name: 'customers.manage_record_comment',\n displayName: 'Manage record comment',\n description:\n 'Create, update, or delete a comment on a person, company, or deal record. Mutation tool \u2014 every call routes through the AI pending-action approval gate. Use `operation` to pick the action; for `create` provide `personId` OR `companyId` (and optionally `dealId`).',\n inputSchema: manageRecordCommentInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordCommentInput = manageRecordCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId\n // We do not load the host person/company entity here \u2014 the\n // `customers/comments` POST handler validates its existence and tenant\n // scope. We do hydrate the deal when supplied so the approval card has\n // a stable record-version anchor.\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { commentId: null, body: null, entityId, dealId: deal.id },\n }\n }\n return {\n recordId: entityId!,\n entityType: input.personId ? 'customers.person' : 'customers.company',\n recordVersion: null,\n before: { commentId: null, body: null, entityId, dealId: null },\n }\n }\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_comment',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n body: existing.body ?? null,\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n entityId: commentEntityIdOf(existing),\n authorUserId: existing.authorUserId ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordCommentInput = manageRecordCommentInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId!\n // Resolve organization scope: prefer the deal's org when one is supplied,\n // otherwise fall back to the caller context's org.\n let organizationId: string | null = ctx.organizationId\n let dealId: string | null = null\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n organizationId = deal.organizationId ?? organizationId\n dealId = deal.id\n }\n if (!organizationId) {\n throw new Error('Organization scope is required to create a comment.')\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n entityId,\n body: input.body,\n }\n if (dealId) body.dealId = dealId\n const response = await runner.run({ method: 'POST', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create comment')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n commentId: result.id ?? null,\n entityId,\n dealId,\n commandName: 'customers.comments.create',\n before: null,\n after: { body: input.body ?? null, entityId, dealId },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Comment \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = {\n id: existing.id,\n tenantId,\n organizationId,\n body: input.body,\n }\n const response = await runner.run({ method: 'PUT', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update comment \"${existing.id}\"`)\n }\n const after = await loadCommentForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n commentId: existing.id,\n commandName: 'customers.comments.update',\n before: { body: existing.body ?? null },\n after: after ? { body: after.body ?? null } : null,\n }\n }\n\n // delete\n const existing = await loadCommentForScope(em, ctx, tenantId, input.commentId!)\n if (!existing) throw new Error(`Comment \"${input.commentId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/comments', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete comment \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n commentId: existing.id,\n commandName: 'customers.comments.delete',\n before: { body: existing.body ?? null },\n after: null,\n }\n },\n}\n\n// ---------------------------------------------------------------------------\n// customers.manage_record_activity \u2014 create / update / delete an activity on\n// a person, company, or deal record. Mutation tool.\n// ---------------------------------------------------------------------------\n\nconst manageRecordActivityInput = z\n .object({\n operation: z\n .enum(['create', 'update', 'delete'])\n .describe('Which write to perform: create a new activity, update an existing one, or delete it.'),\n activityId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `update` and `delete`.'),\n personId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `companyId`) \u2014 the person entity the activity is logged on.'),\n companyId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Required for `create` (or supply `personId`) \u2014 the company entity the activity is logged on.'),\n dealId: z\n .preprocess(blankToUndefined, z.string().uuid().optional())\n .describe('Optional on `create` \u2014 when set, the activity is also linked to that deal.'),\n activityType: z\n .preprocess(blankToUndefined, z.string().min(1).max(100).optional())\n .describe('Required for `create` \u2014 e.g. \"call\", \"email\", \"meeting\", \"note\".'),\n subject: z\n .preprocess(blankToUndefined, z.string().max(200).optional())\n .describe('Optional short subject line.'),\n body: z\n .preprocess(blankToUndefined, z.string().max(8000).optional())\n .describe('Optional free-text body.'),\n occurredAt: z\n .preprocess(blankToUndefined, z.string().datetime().optional())\n .describe('ISO-8601 timestamp when the activity occurred. Omit for \"now\" (server-side default applies).'),\n })\n .superRefine((value, ctx) => {\n if (value.operation === 'create') {\n if (!value.personId && !value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide personId or companyId for create.',\n path: ['personId'],\n })\n }\n if (value.personId && value.companyId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'Provide only one of personId or companyId.',\n path: ['personId'],\n })\n }\n if (!value.activityType) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityType is required for create.', path: ['activityType'] })\n }\n if (value.operation === 'update' || value.operation === 'delete') {\n if (!value.activityId) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'activityId is required.', path: ['activityId'] })\n }\n })\n\ntype ManageRecordActivityInput = z.infer<typeof manageRecordActivityInput>\n\nconst manageRecordActivityTool: CustomersAiToolDefinition = {\n name: 'customers.manage_record_activity',\n displayName: 'Manage record activity',\n description:\n 'Create, update, or delete an activity (call, email, meeting, note) on a person, company, or deal record. Mutation tool \u2014 every call routes through the AI pending-action approval gate. For `create` provide `personId` OR `companyId` (and optionally `dealId`).',\n inputSchema: manageRecordActivityInput as z.ZodType<unknown>,\n requiredFeatures: ['customers.activities.manage'],\n tags: ['write', 'customers'],\n isMutation: true,\n loadBeforeRecord: async (rawInput, ctx): Promise<CustomersToolLoadBeforeSingleRecord | null> => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordActivityInput = manageRecordActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) return null\n return {\n recordId: deal.id,\n entityType: 'customers.deal',\n recordVersion: recordVersionFromUpdatedAt(deal.updatedAt),\n before: { activityId: null, dealId: deal.id, entityId },\n }\n }\n return {\n recordId: entityId!,\n entityType: input.personId ? 'customers.person' : 'customers.company',\n recordVersion: null,\n before: { activityId: null, entityId, dealId: null },\n }\n }\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) return null\n return {\n recordId: existing.id,\n entityType: 'customers.customer_activity',\n recordVersion: recordVersionFromUpdatedAt(existing.updatedAt),\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n entityId: activityEntityIdOf(existing),\n dealId: (existing as any).deal && typeof (existing as any).deal === 'object'\n ? (existing as any).deal.id\n : (existing as any).deal ?? null,\n },\n }\n },\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input: ManageRecordActivityInput = manageRecordActivityInput.parse(rawInput)\n const em = resolveEm(ctx)\n const runner = createAiApiOperationRunner(ctx as unknown as AiToolExecutionContext)\n\n if (input.operation === 'create') {\n const entityId = input.personId ?? input.companyId!\n let organizationId: string | null = ctx.organizationId\n let dealId: string | null = null\n if (input.dealId) {\n const deal = await loadDealForScope(em, ctx, tenantId, input.dealId)\n if (!deal) throw new Error(`Deal \"${input.dealId}\" is not accessible to the caller.`)\n organizationId = deal.organizationId ?? organizationId\n dealId = deal.id\n }\n if (!organizationId) {\n throw new Error('Organization scope is required to create an activity.')\n }\n const body: Record<string, unknown> = {\n tenantId,\n organizationId,\n entityId,\n activityType: input.activityType,\n }\n if (dealId) body.dealId = dealId\n if (input.subject) body.subject = input.subject\n if (input.body) body.body = input.body\n if (input.occurredAt) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'POST', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? 'Failed to create activity')\n }\n const result = (response.data ?? {}) as { id?: string | null }\n return {\n operation: 'create' as const,\n activityId: result.id ?? null,\n entityId,\n dealId,\n commandName: 'customers.activities.create',\n before: null,\n after: {\n activityType: input.activityType ?? null,\n subject: input.subject ?? null,\n body: input.body ?? null,\n occurredAt: input.occurredAt ?? null,\n },\n }\n }\n\n if (input.operation === 'update') {\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const organizationId = existing.organizationId\n if (!organizationId) throw new Error(`Activity \"${existing.id}\" has no organization scope.`)\n const body: Record<string, unknown> = { id: existing.id, tenantId, organizationId }\n if (input.activityType) body.activityType = input.activityType\n if (input.subject !== undefined) body.subject = input.subject\n if (input.body !== undefined) body.body = input.body\n if (input.occurredAt !== undefined) body.occurredAt = input.occurredAt\n const response = await runner.run({ method: 'PUT', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to update activity \"${existing.id}\"`)\n }\n const after = await loadActivityForScope(em, ctx, tenantId, existing.id)\n return {\n operation: 'update' as const,\n activityId: existing.id,\n commandName: 'customers.activities.update',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n occurredAt: existing.occurredAt ? new Date(existing.occurredAt).toISOString() : null,\n },\n after: after\n ? {\n activityType: after.activityType,\n subject: after.subject ?? null,\n body: after.body ?? null,\n occurredAt: after.occurredAt ? new Date(after.occurredAt).toISOString() : null,\n }\n : null,\n }\n }\n\n // delete\n const existing = await loadActivityForScope(em, ctx, tenantId, input.activityId!)\n if (!existing) throw new Error(`Activity \"${input.activityId}\" is not accessible to the caller.`)\n const body: Record<string, unknown> = { id: existing.id }\n const response = await runner.run({ method: 'DELETE', path: '/customers/activities', body })\n if (!response.success) {\n throw new Error(response.error ?? `Failed to delete activity \"${existing.id}\"`)\n }\n return {\n operation: 'delete' as const,\n activityId: existing.id,\n commandName: 'customers.activities.delete',\n before: {\n activityType: existing.activityType,\n subject: existing.subject ?? null,\n body: existing.body ?? null,\n },\n after: null,\n }\n },\n}\n\nexport const activitiesTasksAiTools: CustomersAiToolDefinition[] = [\n listActivitiesTool,\n listTasksTool,\n listDealCommentsTool,\n manageDealCommentTool,\n manageDealActivityTool,\n listRecordCommentsTool,\n manageRecordCommentTool,\n manageRecordActivityTool,\n]\n\nexport default activitiesTasksAiTools\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["body", "response", "existing"]
|
|
7
7
|
}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
resolveCompanyCustomFieldRouting,
|
|
25
25
|
mergeCompanyCustomFieldValues
|
|
26
26
|
} from "../../../lib/customFieldRouting.js";
|
|
27
|
+
import { isOpenInteractionStatus, TERMINAL_INTERACTION_STATUS_LIST } from "../../../lib/interactionStatus.js";
|
|
27
28
|
import {
|
|
28
29
|
CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,
|
|
29
30
|
EXAMPLE_TODO_SOURCE,
|
|
@@ -496,7 +497,7 @@ async function GET(_req, ctx) {
|
|
|
496
497
|
interactions: canonicalActiveInteractions,
|
|
497
498
|
enrich: includeInteractions
|
|
498
499
|
}) : [];
|
|
499
|
-
const plannedPreviewRows = canonicalActiveInteractions.length > 0 ? canonicalActiveInteractions.filter((interaction) => interaction.status
|
|
500
|
+
const plannedPreviewRows = canonicalActiveInteractions.length > 0 ? canonicalActiveInteractions.filter((interaction) => isOpenInteractionStatus(interaction.status) && interaction.interactionType !== "task").sort((left, right) => {
|
|
500
501
|
const leftTime = new Date(left.scheduledAt ?? left.createdAt).getTime();
|
|
501
502
|
const rightTime = new Date(right.scheduledAt ?? right.createdAt).getTime();
|
|
502
503
|
if (leftTime === rightTime) return left.id.localeCompare(right.id);
|
|
@@ -509,7 +510,7 @@ async function GET(_req, ctx) {
|
|
|
509
510
|
organizationId: company.organizationId,
|
|
510
511
|
tenantId: company.tenantId,
|
|
511
512
|
deletedAt: null,
|
|
512
|
-
status:
|
|
513
|
+
status: { $nin: [...TERMINAL_INTERACTION_STATUS_LIST] },
|
|
513
514
|
interactionType: { $ne: "task" },
|
|
514
515
|
...emailVisibilityFilter
|
|
515
516
|
},
|