@open-mercato/core 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +13 -1
- package/dist/helpers/integration/api.js +29 -16
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/auth.js +11 -6
- package/dist/helpers/integration/auth.js.map +3 -3
- package/dist/modules/auth/commands/roles.js +9 -12
- package/dist/modules/auth/commands/roles.js.map +2 -2
- package/dist/modules/catalog/ai-agents-context.js +147 -0
- package/dist/modules/catalog/ai-agents-context.js.map +7 -0
- package/dist/modules/catalog/ai-agents.js +383 -0
- package/dist/modules/catalog/ai-agents.js.map +7 -0
- package/dist/modules/catalog/ai-tools/_shared.js +318 -0
- package/dist/modules/catalog/ai-tools/_shared.js.map +7 -0
- package/dist/modules/catalog/ai-tools/authoring-pack.js +391 -0
- package/dist/modules/catalog/ai-tools/authoring-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/categories-pack.js +167 -0
- package/dist/modules/catalog/ai-tools/categories-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/configuration-pack.js +120 -0
- package/dist/modules/catalog/ai-tools/configuration-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/media-tags-pack.js +107 -0
- package/dist/modules/catalog/ai-tools/media-tags-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +429 -0
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/mutation-pack.js +576 -0
- package/dist/modules/catalog/ai-tools/mutation-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js +208 -0
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/products-pack.js +298 -0
- package/dist/modules/catalog/ai-tools/products-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/stats-pack.js +57 -0
- package/dist/modules/catalog/ai-tools/stats-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/types.js +10 -0
- package/dist/modules/catalog/ai-tools/types.js.map +7 -0
- package/dist/modules/catalog/ai-tools/variants-pack.js +75 -0
- package/dist/modules/catalog/ai-tools/variants-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools.js +28 -0
- package/dist/modules/catalog/ai-tools.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +466 -0
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/page.js +7 -1
- package/dist/modules/catalog/backend/catalog/products/page.js.map +2 -2
- package/dist/modules/catalog/components/CatalogStatsCard.js +91 -0
- package/dist/modules/catalog/components/CatalogStatsCard.js.map +7 -0
- package/dist/modules/catalog/components/products/ProductsDataTable.js +23 -3
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/events.js +7 -4
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +59 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js +17 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
- package/dist/modules/catalog/widgets/injection-table.js +13 -1
- package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +94 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js +17 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js +9 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/ai-agents-context.js +96 -0
- package/dist/modules/customers/ai-agents-context.js.map +7 -0
- package/dist/modules/customers/ai-agents.js +244 -0
- package/dist/modules/customers/ai-agents.js.map +7 -0
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js +1015 -0
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/addresses-tags-pack.js +134 -0
- package/dist/modules/customers/ai-tools/addresses-tags-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/companies-pack.js +249 -0
- package/dist/modules/customers/ai-tools/companies-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/deals-pack.js +348 -0
- package/dist/modules/customers/ai-tools/deals-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/people-pack.js +261 -0
- package/dist/modules/customers/ai-tools/people-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/settings-pack.js +102 -0
- package/dist/modules/customers/ai-tools/settings-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/types.js +10 -0
- package/dist/modules/customers/ai-tools/types.js.map +7 -0
- package/dist/modules/customers/ai-tools.js +20 -0
- package/dist/modules/customers/ai-tools.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +469 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +17 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +117 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js +17 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js.map +7 -0
- package/dist/modules/customers/widgets/injection-table.js +26 -0
- package/dist/modules/customers/widgets/injection-table.js.map +7 -0
- package/dist/modules/inbox_ops/ai-tools.js +4 -0
- package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
- package/dist/modules/inbox_ops/lib/llmProvider.js +52 -7
- package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
- package/dist/modules/notifications/setup.js +13 -0
- package/dist/modules/notifications/setup.js.map +7 -0
- package/jest.config.cjs +1 -0
- package/jest.setup.ts +18 -0
- package/package.json +5 -3
- package/src/helpers/integration/api.ts +38 -16
- package/src/helpers/integration/auth.ts +13 -6
- package/src/modules/auth/commands/roles.ts +10 -12
- package/src/modules/catalog/AGENTS.md +11 -0
- package/src/modules/catalog/ai-agents-context.ts +239 -0
- package/src/modules/catalog/ai-agents.ts +525 -0
- package/src/modules/catalog/ai-tools/_shared.ts +487 -0
- package/src/modules/catalog/ai-tools/authoring-pack.ts +600 -0
- package/src/modules/catalog/ai-tools/categories-pack.ts +192 -0
- package/src/modules/catalog/ai-tools/configuration-pack.ts +218 -0
- package/src/modules/catalog/ai-tools/media-tags-pack.ts +127 -0
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +608 -0
- package/src/modules/catalog/ai-tools/mutation-pack.ts +761 -0
- package/src/modules/catalog/ai-tools/prices-offers-pack.ts +376 -0
- package/src/modules/catalog/ai-tools/products-pack.ts +387 -0
- package/src/modules/catalog/ai-tools/stats-pack.ts +84 -0
- package/src/modules/catalog/ai-tools/types.ts +81 -0
- package/src/modules/catalog/ai-tools/variants-pack.ts +147 -0
- package/src/modules/catalog/ai-tools.ts +78 -0
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +597 -0
- package/src/modules/catalog/backend/catalog/products/page.tsx +23 -2
- package/src/modules/catalog/components/CatalogStatsCard.tsx +118 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +54 -6
- package/src/modules/catalog/events.ts +7 -4
- package/src/modules/catalog/i18n/de.json +17 -0
- package/src/modules/catalog/i18n/en.json +17 -0
- package/src/modules/catalog/i18n/es.json +17 -0
- package/src/modules/catalog/i18n/pl.json +17 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +109 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.ts +29 -0
- package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
- package/src/modules/catalog/widgets/injection-table.ts +12 -0
- package/src/modules/customer_accounts/i18n/de.json +5 -0
- package/src/modules/customer_accounts/i18n/en.json +5 -0
- package/src/modules/customer_accounts/i18n/es.json +5 -0
- package/src/modules/customer_accounts/i18n/pl.json +5 -0
- package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +136 -0
- package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.ts +43 -0
- package/src/modules/customer_accounts/widgets/injection-table.ts +9 -0
- package/src/modules/customers/AGENTS.md +13 -0
- package/src/modules/customers/ai-agents-context.ts +150 -0
- package/src/modules/customers/ai-agents.ts +355 -0
- package/src/modules/customers/ai-tools/activities-tasks-pack.ts +1248 -0
- package/src/modules/customers/ai-tools/addresses-tags-pack.ts +145 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +362 -0
- package/src/modules/customers/ai-tools/deals-pack.ts +505 -0
- package/src/modules/customers/ai-tools/people-pack.ts +369 -0
- package/src/modules/customers/ai-tools/settings-pack.ts +121 -0
- package/src/modules/customers/ai-tools/types.ts +76 -0
- package/src/modules/customers/ai-tools.ts +34 -0
- package/src/modules/customers/i18n/de.json +25 -0
- package/src/modules/customers/i18n/en.json +25 -0
- package/src/modules/customers/i18n/es.json +25 -0
- package/src/modules/customers/i18n/pl.json +25 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +580 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +36 -0
- package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +191 -0
- package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.ts +37 -0
- package/src/modules/customers/widgets/injection-table.ts +41 -0
- package/src/modules/inbox_ops/ai-tools.ts +4 -0
- package/src/modules/inbox_ops/lib/llmProvider.ts +83 -7
- package/src/modules/notifications/setup.ts +11 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CatalogProduct, CatalogProductCategory, CatalogProductTag } from "../data/entities.js";
|
|
3
|
+
import { assertTenantScope } from "./types.js";
|
|
4
|
+
function resolveEm(ctx) {
|
|
5
|
+
return ctx.container.resolve("em");
|
|
6
|
+
}
|
|
7
|
+
const showStatsInput = z.object({
|
|
8
|
+
note: z.string().max(160).optional().describe(
|
|
9
|
+
'Optional one-line note to render below the stats grid (e.g. "as of today" or a quick observation).'
|
|
10
|
+
)
|
|
11
|
+
}).passthrough();
|
|
12
|
+
const showStatsTool = {
|
|
13
|
+
name: "catalog.show_stats",
|
|
14
|
+
displayName: "Show catalog stats",
|
|
15
|
+
description: 'Displays a compact "Catalog overview" card in the chat with live counts: total products, active products, categories, and tags for the current tenant. Use this when the operator asks for a high-level snapshot of the catalog (e.g. "give me catalog stats", "how many products do we have", "show overview"). Returns a `uiPart` envelope so the registered `catalog.stats-card` component renders inline \u2014 no fenced code block needed.',
|
|
16
|
+
inputSchema: showStatsInput,
|
|
17
|
+
requiredFeatures: ["catalog.products.view"],
|
|
18
|
+
tags: ["read", "catalog", "stats", "ui"],
|
|
19
|
+
isMutation: false,
|
|
20
|
+
handler: async (rawInput, ctx) => {
|
|
21
|
+
const { tenantId } = assertTenantScope(ctx);
|
|
22
|
+
const input = showStatsInput.parse(rawInput);
|
|
23
|
+
const em = resolveEm(ctx);
|
|
24
|
+
const tenantScope = { tenantId };
|
|
25
|
+
if (ctx.organizationId) tenantScope.organizationId = ctx.organizationId;
|
|
26
|
+
const softDeleteScope = { ...tenantScope, deletedAt: null };
|
|
27
|
+
const [products, activeProducts, categories, tags] = await Promise.all([
|
|
28
|
+
em.count(CatalogProduct, softDeleteScope),
|
|
29
|
+
em.count(CatalogProduct, { ...softDeleteScope, isActive: true }),
|
|
30
|
+
em.count(CatalogProductCategory, softDeleteScope),
|
|
31
|
+
em.count(CatalogProductTag, tenantScope)
|
|
32
|
+
]);
|
|
33
|
+
return {
|
|
34
|
+
uiPart: {
|
|
35
|
+
componentId: "catalog.stats-card",
|
|
36
|
+
payload: {
|
|
37
|
+
products,
|
|
38
|
+
activeProducts,
|
|
39
|
+
categories,
|
|
40
|
+
tags,
|
|
41
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42
|
+
note: input.note
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
// Plain-text mirror so the model can summarize what it just rendered
|
|
46
|
+
// without parsing the UI part envelope itself.
|
|
47
|
+
summary: `Catalog snapshot: ${products} products (${activeProducts} active), ${categories} categories, ${tags} tags.`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const statsAiTools = [showStatsTool];
|
|
52
|
+
var stats_pack_default = statsAiTools;
|
|
53
|
+
export {
|
|
54
|
+
stats_pack_default as default,
|
|
55
|
+
statsAiTools
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=stats-pack.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/stats-pack.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * `catalog.show_stats` \u2014 example dynamic UI-part tool.\n *\n * Demonstrates the generic UI-part contract: any tool can return a JSON\n * envelope `{ uiPart: { componentId, payload } }` (or a `uiParts: [...]`\n * array) and the chat client surfaces it inline. The catalog stats card\n * is the canonical dynamic example; module authors copy this file +\n * `components/CatalogStatsCard.tsx` to ship their own cards.\n *\n * Read-only \u2014 no `prepareMutation` gate, no DB writes.\n */\n\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { CatalogProduct, CatalogProductCategory, CatalogProductTag } from '../data/entities'\nimport { assertTenantScope, type CatalogAiToolDefinition, type CatalogToolContext } from './types'\n\nfunction resolveEm(ctx: CatalogToolContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nconst showStatsInput = z\n .object({\n note: z\n .string()\n .max(160)\n .optional()\n .describe(\n 'Optional one-line note to render below the stats grid (e.g. \"as of today\" or a quick observation).',\n ),\n })\n .passthrough()\n\nconst showStatsTool: CatalogAiToolDefinition = {\n name: 'catalog.show_stats',\n displayName: 'Show catalog stats',\n description:\n 'Displays a compact \"Catalog overview\" card in the chat with live counts: total products, active products, categories, and tags for the current tenant. Use this when the operator asks for a high-level snapshot of the catalog (e.g. \"give me catalog stats\", \"how many products do we have\", \"show overview\"). Returns a `uiPart` envelope so the registered `catalog.stats-card` component renders inline \u2014 no fenced code block needed.',\n inputSchema: showStatsInput,\n requiredFeatures: ['catalog.products.view'],\n tags: ['read', 'catalog', 'stats', 'ui'],\n isMutation: false,\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = showStatsInput.parse(rawInput)\n const em = resolveEm(ctx)\n\n // CatalogProductTag has no soft-delete column, so the `deletedAt: null`\n // filter (used for products + categories which DO have it) would throw\n // `Trying to query by not existing property CatalogProductTag.deletedAt`.\n // Build per-entity scopes that only include the fields that actually exist.\n const tenantScope: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) tenantScope.organizationId = ctx.organizationId\n const softDeleteScope: Record<string, unknown> = { ...tenantScope, deletedAt: null }\n\n const [products, activeProducts, categories, tags] = await Promise.all([\n em.count(CatalogProduct, softDeleteScope as never),\n em.count(CatalogProduct, { ...softDeleteScope, isActive: true } as never),\n em.count(CatalogProductCategory, softDeleteScope as never),\n em.count(CatalogProductTag, tenantScope as never),\n ])\n\n return {\n uiPart: {\n componentId: 'catalog.stats-card',\n payload: {\n products,\n activeProducts,\n categories,\n tags,\n generatedAt: new Date().toISOString(),\n note: input.note,\n },\n },\n // Plain-text mirror so the model can summarize what it just rendered\n // without parsing the UI part envelope itself.\n summary: `Catalog snapshot: ${products} products (${activeProducts} active), ${categories} categories, ${tags} tags.`,\n }\n },\n}\n\nexport const statsAiTools: CatalogAiToolDefinition[] = [showStatsTool]\n\nexport default statsAiTools\n"],
|
|
5
|
+
"mappings": "AAaA,SAAS,SAAS;AAClB,SAAS,gBAAgB,wBAAwB,yBAAyB;AAC1E,SAAS,yBAAgF;AAEzF,SAAS,UAAU,KAAwC;AACzD,SAAO,IAAI,UAAU,QAAuB,IAAI;AAClD;AAEA,MAAM,iBAAiB,EACpB,OAAO;AAAA,EACN,MAAM,EACH,OAAO,EACP,IAAI,GAAG,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC,EACA,YAAY;AAEf,MAAM,gBAAyC;AAAA,EAC7C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aACE;AAAA,EACF,aAAa;AAAA,EACb,kBAAkB,CAAC,uBAAuB;AAAA,EAC1C,MAAM,CAAC,QAAQ,WAAW,SAAS,IAAI;AAAA,EACvC,YAAY;AAAA,EACZ,SAAS,OAAO,UAAU,QAAQ;AAChC,UAAM,EAAE,SAAS,IAAI,kBAAkB,GAAG;AAC1C,UAAM,QAAQ,eAAe,MAAM,QAAQ;AAC3C,UAAM,KAAK,UAAU,GAAG;AAMxB,UAAM,cAAuC,EAAE,SAAS;AACxD,QAAI,IAAI,eAAgB,aAAY,iBAAiB,IAAI;AACzD,UAAM,kBAA2C,EAAE,GAAG,aAAa,WAAW,KAAK;AAEnF,UAAM,CAAC,UAAU,gBAAgB,YAAY,IAAI,IAAI,MAAM,QAAQ,IAAI;AAAA,MACrE,GAAG,MAAM,gBAAgB,eAAwB;AAAA,MACjD,GAAG,MAAM,gBAAgB,EAAE,GAAG,iBAAiB,UAAU,KAAK,CAAU;AAAA,MACxE,GAAG,MAAM,wBAAwB,eAAwB;AAAA,MACzD,GAAG,MAAM,mBAAmB,WAAoB;AAAA,IAClD,CAAC;AAED,WAAO;AAAA,MACL,QAAQ;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,MAAM,MAAM;AAAA,QACd;AAAA,MACF;AAAA;AAAA;AAAA,MAGA,SAAS,qBAAqB,QAAQ,cAAc,cAAc,aAAa,UAAU,gBAAgB,IAAI;AAAA,IAC/G;AAAA,EACF;AACF;AAEO,MAAM,eAA0C,CAAC,aAAa;AAErE,IAAO,qBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function assertTenantScope(ctx) {
|
|
2
|
+
if (!ctx.tenantId) {
|
|
3
|
+
throw new Error("Tenant context is required for catalog.* tools");
|
|
4
|
+
}
|
|
5
|
+
return { tenantId: ctx.tenantId, organizationId: ctx.organizationId };
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
assertTenantScope
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/types.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Local AI tool shape for the catalog module (Phase 1 WS-C, Step 3.10).\n *\n * Mirrors the pattern established by the customers pack (Step 3.9): the\n * catalog module declares its read-only tools as plain objects whose shape\n * is a strict subset of `AiToolDefinition` from `@open-mercato/ai-assistant`.\n * Keeping the shape local avoids pulling the ai-assistant package into the\n * core module graph for jest and sidesteps a cross-package `moduleNameMapper`.\n * The generator walks every module root for a default / `aiTools` export with\n * this shape.\n */\nimport type { z } from 'zod'\nimport type { AwilixContainer } from 'awilix'\n\nexport interface CatalogToolContext {\n tenantId: string | null\n organizationId: string | null\n userId: string | null\n container: AwilixContainer\n userFeatures: string[]\n isSuperAdmin: boolean\n apiKeySecret?: string\n sessionId?: string\n}\n\n/**\n * Shape returned by `loadBeforeRecord` on a single-record mutation tool.\n * Mirrors `AiToolLoadBeforeSingleRecord` from `@open-mercato/ai-assistant/lib/types`.\n */\nexport interface CatalogToolLoadBeforeSingleRecord {\n recordId: string\n entityType: string\n recordVersion: string | null\n before: Record<string, unknown>\n}\n\n/**\n * Shape returned by `loadBeforeRecords` on a bulk mutation tool. Mirrors\n * `AiToolLoadBeforeRecord` from `@open-mercato/ai-assistant/lib/types` \u2014 the\n * Step 5.6 `prepareMutation` runtime wraps this into the `records[]` array on\n * the emitted `mutation-preview-card`.\n */\nexport interface CatalogToolLoadBeforeRecord {\n recordId: string\n entityType: string\n label: string\n recordVersion: string | null\n before: Record<string, unknown>\n}\n\nexport interface CatalogAiToolDefinition<TInput = unknown, TOutput = unknown> {\n name: string\n displayName?: string\n description: string\n inputSchema: z.ZodType<TInput>\n requiredFeatures?: string[]\n tags?: string[]\n isMutation?: boolean\n isBulk?: boolean\n maxCallsPerTurn?: number\n supportsAttachments?: boolean\n handler: (input: TInput, context: CatalogToolContext) => Promise<TOutput>\n loadBeforeRecord?: (\n input: TInput,\n context: CatalogToolContext,\n ) => Promise<CatalogToolLoadBeforeSingleRecord | null>\n loadBeforeRecords?: (\n input: TInput,\n context: CatalogToolContext,\n ) => Promise<CatalogToolLoadBeforeRecord[]>\n}\n\nexport function assertTenantScope(ctx: CatalogToolContext): {\n tenantId: string\n organizationId: string | null\n} {\n if (!ctx.tenantId) {\n throw new Error('Tenant context is required for catalog.* tools')\n }\n return { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n}\n"],
|
|
5
|
+
"mappings": "AAwEO,SAAS,kBAAkB,KAGhC;AACA,MAAI,CAAC,IAAI,UAAU;AACjB,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,SAAO,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AACtE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineApiBackedAiTool } from "@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool";
|
|
3
|
+
import { assertTenantScope } from "./types.js";
|
|
4
|
+
const listVariantsInput = z.object({
|
|
5
|
+
productId: z.string().uuid().describe("Parent product id (UUID)."),
|
|
6
|
+
limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
|
|
7
|
+
offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
|
|
8
|
+
}).passthrough();
|
|
9
|
+
const listVariantsTool = defineApiBackedAiTool({
|
|
10
|
+
name: "catalog.list_variants",
|
|
11
|
+
displayName: "List variants",
|
|
12
|
+
description: "List the variants of a catalog product (including option values, SKU, barcode, default media ref). Returns { items, total, limit, offset }.",
|
|
13
|
+
inputSchema: listVariantsInput,
|
|
14
|
+
requiredFeatures: ["catalog.products.view"],
|
|
15
|
+
toOperation: (input, ctx) => {
|
|
16
|
+
assertTenantScope(ctx);
|
|
17
|
+
const limit = input.limit ?? 50;
|
|
18
|
+
const offset = input.offset ?? 0;
|
|
19
|
+
const page = Math.floor(offset / limit) + 1;
|
|
20
|
+
const query = {
|
|
21
|
+
page,
|
|
22
|
+
pageSize: limit,
|
|
23
|
+
productId: input.productId
|
|
24
|
+
};
|
|
25
|
+
const operation = {
|
|
26
|
+
method: "GET",
|
|
27
|
+
path: "/catalog/variants",
|
|
28
|
+
query
|
|
29
|
+
};
|
|
30
|
+
return operation;
|
|
31
|
+
},
|
|
32
|
+
mapResponse: (response, input) => {
|
|
33
|
+
const limit = input.limit ?? 50;
|
|
34
|
+
const offset = input.offset ?? 0;
|
|
35
|
+
const data = response.data ?? {};
|
|
36
|
+
const rawItems = Array.isArray(data.items) ? data.items : [];
|
|
37
|
+
return {
|
|
38
|
+
items: rawItems.map((row) => {
|
|
39
|
+
const createdAtRaw = row.created_at ?? row.createdAt ?? null;
|
|
40
|
+
const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null;
|
|
41
|
+
return {
|
|
42
|
+
id: row.id,
|
|
43
|
+
name: row.name ?? null,
|
|
44
|
+
sku: row.sku ?? null,
|
|
45
|
+
barcode: row.barcode ?? null,
|
|
46
|
+
statusEntryId: row.status_entry_id ?? row.statusEntryId ?? null,
|
|
47
|
+
optionValues: row.option_values ?? row.optionValues ?? null,
|
|
48
|
+
defaultMediaId: row.default_media_id ?? row.defaultMediaId ?? null,
|
|
49
|
+
defaultMediaUrl: row.default_media_url ?? row.defaultMediaUrl ?? null,
|
|
50
|
+
weightValue: row.weight_value ?? row.weightValue ?? null,
|
|
51
|
+
weightUnit: row.weight_unit ?? row.weightUnit ?? null,
|
|
52
|
+
dimensions: row.dimensions ?? null,
|
|
53
|
+
taxRate: row.tax_rate ?? row.taxRate ?? null,
|
|
54
|
+
taxRateId: row.tax_rate_id ?? row.taxRateId ?? null,
|
|
55
|
+
isDefault: !!(row.is_default ?? row.isDefault),
|
|
56
|
+
isActive: !!(row.is_active ?? row.isActive),
|
|
57
|
+
productId: row.product_id ?? row.productId ?? null,
|
|
58
|
+
organizationId: row.organization_id ?? row.organizationId ?? null,
|
|
59
|
+
tenantId: row.tenant_id ?? row.tenantId ?? null,
|
|
60
|
+
createdAt
|
|
61
|
+
};
|
|
62
|
+
}),
|
|
63
|
+
total: typeof data.total === "number" ? data.total : 0,
|
|
64
|
+
limit,
|
|
65
|
+
offset
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
const variantsAiTools = [listVariantsTool];
|
|
70
|
+
var variants_pack_default = variantsAiTools;
|
|
71
|
+
export {
|
|
72
|
+
variants_pack_default as default,
|
|
73
|
+
variantsAiTools
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=variants-pack.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/variants-pack.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * `catalog.list_variants` (Phase 1 WS-C, Step 3.10).\n *\n * Enumerate variants for a single product with option values + media refs.\n *\n * Phase 3b of `.ai/specs/2026-04-27-ai-tools-api-backed-dry-refactor.md`:\n * `catalog.list_variants` is now an API-backed wrapper over\n * `GET /api/catalog/variants`. Tool name, schema, requiredFeatures, and\n * output shape are unchanged.\n */\nimport { z } from 'zod'\nimport { defineApiBackedAiTool } from '@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool'\nimport type {\n AiApiOperationRequest,\n AiToolExecutionContext,\n} from '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner'\nimport { assertTenantScope, type CatalogAiToolDefinition, type CatalogToolContext } from './types'\n\nconst listVariantsInput = z\n .object({\n productId: z.string().uuid().describe('Parent product id (UUID).'),\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\ntype ListVariantsInput = z.infer<typeof listVariantsInput>\n\ntype ListVariantsApiItem = {\n id?: string\n product_id?: string | null\n productId?: string | null\n name?: string | null\n sku?: string | null\n barcode?: string | null\n status_entry_id?: string | null\n statusEntryId?: string | null\n option_values?: unknown\n optionValues?: unknown\n default_media_id?: string | null\n defaultMediaId?: string | null\n default_media_url?: string | null\n defaultMediaUrl?: string | null\n weight_value?: string | number | null\n weightValue?: string | number | null\n weight_unit?: string | null\n weightUnit?: string | null\n dimensions?: unknown\n tax_rate?: string | number | null\n taxRate?: string | number | null\n tax_rate_id?: string | null\n taxRateId?: string | null\n is_default?: boolean | null\n isDefault?: boolean | null\n is_active?: boolean | null\n isActive?: boolean | null\n organization_id?: string | null\n organizationId?: string | null\n tenant_id?: string | null\n tenantId?: string | null\n created_at?: string | null\n createdAt?: string | null\n}\n\ntype ListVariantsApiResponse = {\n items?: ListVariantsApiItem[]\n total?: number\n}\n\ntype ListVariantsOutput = {\n items: Array<Record<string, unknown>>\n total: number\n limit: number\n offset: number\n}\n\nconst listVariantsTool = defineApiBackedAiTool<\n ListVariantsInput,\n ListVariantsApiResponse,\n ListVariantsOutput\n>({\n name: 'catalog.list_variants',\n displayName: 'List variants',\n description:\n 'List the variants of a catalog product (including option values, SKU, barcode, default media ref). Returns { items, total, limit, offset }.',\n inputSchema: listVariantsInput,\n requiredFeatures: ['catalog.products.view'],\n toOperation: (input, ctx) => {\n assertTenantScope(ctx as unknown as CatalogToolContext)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const page = Math.floor(offset / limit) + 1\n\n const query: Record<string, string | number | boolean | null | undefined> = {\n page,\n pageSize: limit,\n productId: input.productId,\n }\n\n const operation: AiApiOperationRequest = {\n method: 'GET',\n path: '/catalog/variants',\n query,\n }\n return operation\n },\n mapResponse: (response, input) => {\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const data = (response.data ?? {}) as ListVariantsApiResponse\n const rawItems: ListVariantsApiItem[] = Array.isArray(data.items) ? data.items : []\n return {\n items: rawItems.map((row) => {\n const createdAtRaw = row.created_at ?? row.createdAt ?? null\n const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null\n return {\n id: row.id,\n name: row.name ?? null,\n sku: row.sku ?? null,\n barcode: row.barcode ?? null,\n statusEntryId: row.status_entry_id ?? row.statusEntryId ?? null,\n optionValues: row.option_values ?? row.optionValues ?? null,\n defaultMediaId: row.default_media_id ?? row.defaultMediaId ?? null,\n defaultMediaUrl: row.default_media_url ?? row.defaultMediaUrl ?? null,\n weightValue: row.weight_value ?? row.weightValue ?? null,\n weightUnit: row.weight_unit ?? row.weightUnit ?? null,\n dimensions: row.dimensions ?? null,\n taxRate: row.tax_rate ?? row.taxRate ?? null,\n taxRateId: row.tax_rate_id ?? row.taxRateId ?? null,\n isDefault: !!(row.is_default ?? row.isDefault),\n isActive: !!(row.is_active ?? row.isActive),\n productId: row.product_id ?? row.productId ?? null,\n organizationId: row.organization_id ?? row.organizationId ?? null,\n tenantId: row.tenant_id ?? row.tenantId ?? null,\n createdAt,\n }\n }),\n total: typeof data.total === 'number' ? data.total : 0,\n limit,\n offset,\n }\n },\n}) as unknown as CatalogAiToolDefinition\n\nexport const variantsAiTools: CatalogAiToolDefinition[] = [listVariantsTool]\n\nexport default variantsAiTools\n"],
|
|
5
|
+
"mappings": "AAUA,SAAS,SAAS;AAClB,SAAS,6BAA6B;AAKtC,SAAS,yBAAgF;AAEzF,MAAM,oBAAoB,EACvB,OAAO;AAAA,EACN,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,2BAA2B;AAAA,EACjE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,iCAAiC;AAAA,EAC7F,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,2BAA2B;AACjF,CAAC,EACA,YAAY;AAoDf,MAAM,mBAAmB,sBAIvB;AAAA,EACA,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aACE;AAAA,EACF,aAAa;AAAA,EACb,kBAAkB,CAAC,uBAAuB;AAAA,EAC1C,aAAa,CAAC,OAAO,QAAQ;AAC3B,sBAAkB,GAAoC;AACtD,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,OAAO,KAAK,MAAM,SAAS,KAAK,IAAI;AAE1C,UAAM,QAAsE;AAAA,MAC1E;AAAA,MACA,UAAU;AAAA,MACV,WAAW,MAAM;AAAA,IACnB;AAEA,UAAM,YAAmC;AAAA,MACvC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EACA,aAAa,CAAC,UAAU,UAAU;AAChC,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,OAAQ,SAAS,QAAQ,CAAC;AAChC,UAAM,WAAkC,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;AAClF,WAAO;AAAA,MACL,OAAO,SAAS,IAAI,CAAC,QAAQ;AAC3B,cAAM,eAAe,IAAI,cAAc,IAAI,aAAa;AACxD,cAAM,YAAY,eAAe,IAAI,KAAK,OAAO,YAAY,CAAC,EAAE,YAAY,IAAI;AAChF,eAAO;AAAA,UACL,IAAI,IAAI;AAAA,UACR,MAAM,IAAI,QAAQ;AAAA,UAClB,KAAK,IAAI,OAAO;AAAA,UAChB,SAAS,IAAI,WAAW;AAAA,UACxB,eAAe,IAAI,mBAAmB,IAAI,iBAAiB;AAAA,UAC3D,cAAc,IAAI,iBAAiB,IAAI,gBAAgB;AAAA,UACvD,gBAAgB,IAAI,oBAAoB,IAAI,kBAAkB;AAAA,UAC9D,iBAAiB,IAAI,qBAAqB,IAAI,mBAAmB;AAAA,UACjE,aAAa,IAAI,gBAAgB,IAAI,eAAe;AAAA,UACpD,YAAY,IAAI,eAAe,IAAI,cAAc;AAAA,UACjD,YAAY,IAAI,cAAc;AAAA,UAC9B,SAAS,IAAI,YAAY,IAAI,WAAW;AAAA,UACxC,WAAW,IAAI,eAAe,IAAI,aAAa;AAAA,UAC/C,WAAW,CAAC,EAAE,IAAI,cAAc,IAAI;AAAA,UACpC,UAAU,CAAC,EAAE,IAAI,aAAa,IAAI;AAAA,UAClC,WAAW,IAAI,cAAc,IAAI,aAAa;AAAA,UAC9C,gBAAgB,IAAI,mBAAmB,IAAI,kBAAkB;AAAA,UAC7D,UAAU,IAAI,aAAa,IAAI,YAAY;AAAA,UAC3C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,MACD,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,MAAM,kBAA6C,CAAC,gBAAgB;AAE3E,IAAO,wBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import productsAiTools from "./ai-tools/products-pack.js";
|
|
2
|
+
import categoriesAiTools from "./ai-tools/categories-pack.js";
|
|
3
|
+
import variantsAiTools from "./ai-tools/variants-pack.js";
|
|
4
|
+
import pricesOffersAiTools from "./ai-tools/prices-offers-pack.js";
|
|
5
|
+
import mediaTagsAiTools from "./ai-tools/media-tags-pack.js";
|
|
6
|
+
import configurationAiTools from "./ai-tools/configuration-pack.js";
|
|
7
|
+
import merchandisingAiTools from "./ai-tools/merchandising-pack.js";
|
|
8
|
+
import authoringAiTools from "./ai-tools/authoring-pack.js";
|
|
9
|
+
import mutationAiTools from "./ai-tools/mutation-pack.js";
|
|
10
|
+
import statsAiTools from "./ai-tools/stats-pack.js";
|
|
11
|
+
const aiTools = [
|
|
12
|
+
...productsAiTools,
|
|
13
|
+
...categoriesAiTools,
|
|
14
|
+
...variantsAiTools,
|
|
15
|
+
...pricesOffersAiTools,
|
|
16
|
+
...mediaTagsAiTools,
|
|
17
|
+
...configurationAiTools,
|
|
18
|
+
...merchandisingAiTools,
|
|
19
|
+
...authoringAiTools,
|
|
20
|
+
...mutationAiTools,
|
|
21
|
+
...statsAiTools
|
|
22
|
+
];
|
|
23
|
+
var ai_tools_default = aiTools;
|
|
24
|
+
export {
|
|
25
|
+
aiTools,
|
|
26
|
+
ai_tools_default as default
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=ai-tools.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/catalog/ai-tools.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Module-root AI tool contribution for the catalog module\n * (Phase 1 WS-C, Steps 3.10 + 3.11 + 3.12 \u2014 read-only Phase 1 coverage;\n * Phase 3 WS-C, Step 5.14 \u2014 D18 mutation pack under the pending-action\n * approval contract).\n *\n * The generator walks every module for a top-level `ai-tools.ts` and takes\n * the default/`aiTools` export as the contribution. This file aggregates the\n * eight catalog packs (products, categories, variants, prices + offers,\n * media + tags, product configuration, D18 merchandising, D18 authoring)\n * so they all flow through the existing `ai-tools.generated.ts` pipeline\n * without any generator changes.\n *\n * Step 5.14 (D18) adds the four mutation tools in `mutation-pack.ts`:\n * - `catalog.update_product`\n * - `catalog.bulk_update_products`\n * - `catalog.apply_attribute_extraction`\n * - `catalog.update_product_media_descriptions`\n *\n * These route through the Step 5.6 `prepareMutation` wrapper and the\n * Step 5.8 confirm route; all other tools remain read-only and enforce\n * tenant + organization scoping via the existing encryption helpers. The Step 3.12 authoring tools are\n * structured-output helpers: they NEVER write and never open a second model\n * call from inside the handler \u2014 the surrounding agent turn performs\n * structured output against the handler's `outputSchemaDescriptor`.\n *\n * Step 3.11 (D18) adds the seven spec-named read tools in\n * `merchandising-pack.ts`:\n * - `catalog.search_products`\n * - `catalog.get_product_bundle`\n * - `catalog.list_selected_products`\n * - `catalog.get_product_media`\n * - `catalog.get_attribute_schema`\n * - `catalog.get_category_brief`\n * - `catalog.list_price_kinds`\n *\n * Step 3.12 (D18) adds the five spec-named AI-authoring tools in\n * `authoring-pack.ts`:\n * - `catalog.draft_description_from_attributes`\n * - `catalog.extract_attributes_from_description`\n * - `catalog.draft_description_from_media`\n * - `catalog.suggest_title_variants`\n * - `catalog.suggest_price_adjustment`\n *\n * `catalog.list_price_kinds` (D18) and `catalog.list_price_kinds_base` (base)\n * coexist as distinct tools \u2014 both route through the shared `listPriceKindsCore`\n * helper in `ai-tools/_shared.ts` so they cannot drift.\n *\n * See `.ai/runs/2026-04-18-ai-framework-unification/step-3.10-checks.md`,\n * `step-3.11-checks.md`, and `step-3.12-checks.md` for the matrix of\n * required features and decisions.\n */\nimport productsAiTools from './ai-tools/products-pack'\nimport categoriesAiTools from './ai-tools/categories-pack'\nimport variantsAiTools from './ai-tools/variants-pack'\nimport pricesOffersAiTools from './ai-tools/prices-offers-pack'\nimport mediaTagsAiTools from './ai-tools/media-tags-pack'\nimport configurationAiTools from './ai-tools/configuration-pack'\nimport merchandisingAiTools from './ai-tools/merchandising-pack'\nimport authoringAiTools from './ai-tools/authoring-pack'\nimport mutationAiTools from './ai-tools/mutation-pack'\nimport statsAiTools from './ai-tools/stats-pack'\nimport type { CatalogAiToolDefinition } from './ai-tools/types'\n\nexport const aiTools: CatalogAiToolDefinition[] = [\n ...productsAiTools,\n ...categoriesAiTools,\n ...variantsAiTools,\n ...pricesOffersAiTools,\n ...mediaTagsAiTools,\n ...configurationAiTools,\n ...merchandisingAiTools,\n ...authoringAiTools,\n ...mutationAiTools,\n ...statsAiTools,\n]\n\nexport default aiTools\n"],
|
|
5
|
+
"mappings": "AAoDA,OAAO,qBAAqB;AAC5B,OAAO,uBAAuB;AAC9B,OAAO,qBAAqB;AAC5B,OAAO,yBAAyB;AAChC,OAAO,sBAAsB;AAC7B,OAAO,0BAA0B;AACjC,OAAO,0BAA0B;AACjC,OAAO,sBAAsB;AAC7B,OAAO,qBAAqB;AAC5B,OAAO,kBAAkB;AAGlB,MAAM,UAAqC;AAAA,EAChD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,IAAO,mBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|