@ikas/code-components-mcp 1.4.0-beta.165 → 1.4.0-beta.167

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-08-18T15:07:09.984Z",
2
+ "generatedAt": "2026-08-19T12:18:27.436Z",
3
3
  "functions": [
4
4
  {
5
5
  "name": "apiListProductBrand",
@@ -12589,11 +12589,27 @@
12589
12589
  "name": "bs_searchProductById",
12590
12590
  "displayName": "searchProductById",
12591
12591
  "signature": "async function bs_searchProductById(baseStore: BaseStore, params: { productId: string }): Promise<{\n isSuccess: boolean;\n product: IkasProduct | null;\n}>",
12592
- "description": "",
12593
- "params": [],
12592
+ "description": "Fetches a single product by id and returns it as a full `IkasProduct`.\n\nUse this when a lightweight reference (e.g. a cart line's `IkasOrderLineVariant`, which carries\nneither `salesChannels` nor `stock`) needs product-level data: the returned product includes\n`salesChannels` filtered to the active sales channel (with `minQuantityPerCart` /\n`maxQuantityPerCart`) and per-variant `stock` (summed over the sales channel's configured\nstock locations). `selectedVariantValues` is seeded from the first active variant (or the\nfirst variant when none is active). For multiple ids, prefer `bs_searchProductsById` — one\nbatched request.",
12593
+ "params": [
12594
+ {
12595
+ "name": "baseStore",
12596
+ "description": "- The base store instance"
12597
+ },
12598
+ {
12599
+ "name": "params",
12600
+ "description": "- `{ productId }` — id of the product to fetch"
12601
+ }
12602
+ ],
12603
+ "returns": "`{ isSuccess, product }` — `product` is null when not found or on failure",
12594
12604
  "returnType": "Promise<{\n isSuccess: boolean;\n product: IkasProduct | null;\n}>",
12595
- "categories": [],
12596
- "related": [],
12605
+ "example": "```tsx\nimport { baseStore, bs_searchProductById, IkasStorefrontConfig } from \"@ikas/bp-storefront\";\n\nconst { isSuccess, product } = await bs_searchProductById(baseStore, { productId });\nif (isSuccess && product) {\n const channel = product.salesChannels?.find(sc => sc.id === IkasStorefrontConfig.salesChannelId);\n console.log(channel?.maxQuantityPerCart);\n}\n```",
12606
+ "categories": [
12607
+ "Product",
12608
+ "Search"
12609
+ ],
12610
+ "related": [
12611
+ "bs_searchProductsById"
12612
+ ],
12597
12613
  "isAsync": true,
12598
12614
  "isClass": false,
12599
12615
  "parameterTypes": [
@@ -12604,11 +12620,29 @@
12604
12620
  "name": "bs_searchProductsById",
12605
12621
  "displayName": "searchProductsById",
12606
12622
  "signature": "async function bs_searchProductsById(baseStore: BaseStore, params: { productIds: string[] }): Promise<{\n isSuccess: boolean;\n products: IkasProduct[] | null;\n}>",
12607
- "description": "",
12608
- "params": [],
12623
+ "description": "Batch-fetches products by id in a single request and returns them as full `IkasProduct` objects.\n\nThe go-to function when cart lines (or any lightweight reference) need product-level data they\ndo not carry: `IkasOrderLineVariant` has neither `salesChannels` nor `stock`, while the products\nreturned here include `salesChannels` filtered to the active sales channel (with\n`minQuantityPerCart` / `maxQuantityPerCart`) and per-variant `stock` (summed over the sales\nchannel's configured stock locations). Collect the distinct `productId`s of the lines and\nfetch them in ONE call instead of one request per line. Called with an empty `productIds`,\nit returns `{ isSuccess: true, products: [] }` without a network request.",
12624
+ "params": [
12625
+ {
12626
+ "name": "baseStore",
12627
+ "description": "- The base store instance"
12628
+ },
12629
+ {
12630
+ "name": "params",
12631
+ "description": "- `{ productIds }` — product ids to fetch (deduplicate before calling)"
12632
+ }
12633
+ ],
12634
+ "returns": "`{ isSuccess, products }` — `products` is null on failure",
12609
12635
  "returnType": "Promise<{\n isSuccess: boolean;\n products: IkasProduct[] | null;\n}>",
12610
- "categories": [],
12611
- "related": [],
12636
+ "example": "```tsx\nimport { baseStore, bs_searchProductsById, cartStore, IkasStorefrontConfig } from \"@ikas/bp-storefront\";\n\n// Enforce per-cart quantity limits on cart lines:\nconst productIds = [\n ...new Set(\n (cartStore.cart?.orderLineItems ?? [])\n .map(item => item.variant.productId)\n .filter((id): id is string => !!id)\n ),\n];\nconst { products } = await bs_searchProductsById(baseStore, { productIds });\nconst maxByProductId = new Map<string, number | null>();\nfor (const p of products ?? []) {\n const channel = p.salesChannels?.find(sc => sc.id === IkasStorefrontConfig.salesChannelId);\n maxByProductId.set(p.id, channel?.maxQuantityPerCart ?? null);\n}\n```",
12637
+ "categories": [
12638
+ "Product",
12639
+ "Cart",
12640
+ "Search"
12641
+ ],
12642
+ "related": [
12643
+ "bs_searchProductById",
12644
+ "changeItemQuantity"
12645
+ ],
12612
12646
  "isAsync": true,
12613
12647
  "isClass": false,
12614
12648
  "parameterTypes": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-08-18T15:07:10.008Z",
2
+ "generatedAt": "2026-08-19T12:18:27.461Z",
3
3
  "types": [
4
4
  {
5
5
  "name": "TextElementTagTypes",
package/dist/index.js CHANGED
@@ -1682,6 +1682,44 @@ function suggestClosestNames(input, candidates, opts) {
1682
1682
  .sort((a, b) => a.d - b.d);
1683
1683
  return edits.slice(0, max).map((s) => s.name);
1684
1684
  }
1685
+ /**
1686
+ * Formatted ` — matching sections: ...` suffix naming the guide sections that match the query,
1687
+ * so a hit buried mid-guide (e.g. "Quantity Limits" inside cart-patterns) is visible without
1688
+ * opening the full guide. Section bodies are scored on purpose: a query for an identifier that
1689
+ * appears only inside a section (an error code, a prop name) must still surface that section's
1690
+ * heading. Returns "" when the query matches most of the guide's sections — matchScore is
1691
+ * presence-based, so a broad query ("cart" against cart-patterns) ties every section and a
1692
+ * top-3 would just echo document order, hinting nothing.
1693
+ */
1694
+ function sectionHint(content, query) {
1695
+ // Line walk instead of a heading-regex split: a `## ` line inside a fenced code block must
1696
+ // not become a pseudo-section (it would surface a heading that doesn't exist in the guide
1697
+ // and swallow the rest of the real section's body).
1698
+ const sections = [];
1699
+ let fenceOpen = false;
1700
+ for (const line of content.split("\n")) {
1701
+ if (/^\s*```/.test(line))
1702
+ fenceOpen = !fenceOpen;
1703
+ const headingMatch = fenceOpen ? null : line.match(/^#{2,4} (.+)/);
1704
+ if (headingMatch)
1705
+ sections.push({ heading: headingMatch[1].trim(), body: "" });
1706
+ else if (sections.length > 0)
1707
+ sections[sections.length - 1].body += line + "\n";
1708
+ }
1709
+ const scored = [];
1710
+ for (const { heading, body } of sections) {
1711
+ // Heading hits weigh double. The floor of 3 drops sections whose only signal is a single
1712
+ // squashed-identifier body match (worth 2) — a literal word hit (3) or any heading match
1713
+ // clears it.
1714
+ const score = matchScore(heading, query) * 2 + matchScore(body, query);
1715
+ if (score >= 3)
1716
+ scored.push({ heading, score });
1717
+ }
1718
+ if (scored.length === 0 || scored.length > sections.length / 2)
1719
+ return "";
1720
+ const top = scored.sort((a, b) => b.score - a.score).slice(0, 3);
1721
+ return ` — matching sections: ${top.map((s) => `"${s.heading}"`).join(", ")}`;
1722
+ }
1685
1723
  function searchFunctions(query) {
1686
1724
  const scored = storefrontData.functions
1687
1725
  .map((fn) => {
@@ -1919,7 +1957,7 @@ server.tool("search_docs", "Search across all ikas storefront API docs, framewor
1919
1957
  if (topics.length > 0) {
1920
1958
  parts.push("\n## Matching Framework Topics\n");
1921
1959
  for (const item of topics) {
1922
- parts.push(`- **${item.topic.title}** (key: \`${item.key}\`) - ${item.topic.description}`);
1960
+ parts.push(`- **${item.topic.title}** (key: \`${item.key}\`) - ${item.topic.description}${sectionHint(item.topic.content, query)}`);
1923
1961
  }
1924
1962
  parts.push("");
1925
1963
  parts.push("Use `get_framework_guide(topic)` to get full content for any topic.");
@@ -1935,7 +1973,7 @@ server.tool("search_docs", "Search across all ikas storefront API docs, framewor
1935
1973
  if (migrationTopics.length > 0) {
1936
1974
  parts.push("\n## Matching Migration Topics\n");
1937
1975
  for (const item of migrationTopics) {
1938
- parts.push(`- [migration] **${item.topic.title}** (key: \`${item.key}\`) - ${item.topic.description}`);
1976
+ parts.push(`- [migration] **${item.topic.title}** (key: \`${item.key}\`) - ${item.topic.description}${sectionHint(item.topic.content, query)}`);
1939
1977
  }
1940
1978
  parts.push("");
1941
1979
  parts.push("Use `get_migration_guide(topic)` to get full content for any migration topic.");