salai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Salai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # salai
2
+
3
+ > Salai grocery intelligence CLI — search products, compare prices, and manage your cart from the terminal.
4
+
5
+ ```bash
6
+ npx salai search "חלב"
7
+ npx salai retailers
8
+ npx salai cart add 7290019489443
9
+ ```
10
+
11
+ > **Looking for MCP integration?** See [`@salai/mcp`](../mcp-cli) for Cursor / Claude Desktop.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ # Use directly with npx (no install needed)
17
+ npx salai <command>
18
+
19
+ # Or install globally
20
+ npm i -g salai
21
+ salai <command>
22
+ ```
23
+
24
+ ## Setup
25
+
26
+ ```bash
27
+ export SALAI_API_KEY="your-api-key-here" # add to ~/.zshrc or ~/.bashrc
28
+ ```
29
+
30
+ Get your API key from the Salai app → **Profile → API Key → Generate**.
31
+
32
+ ---
33
+
34
+ ## Commands
35
+
36
+ ### Global Options
37
+
38
+ ```
39
+ salai [options] <command>
40
+
41
+ -k, --api-key <key> Salai API key (or SALAI_API_KEY env var)
42
+ --url <url> MCP endpoint URL (default: https://mcp.salai.co.il/mcp)
43
+ --json Output raw JSON instead of formatted tables
44
+ -v, --version Print version
45
+ -h, --help Show help
46
+ ```
47
+
48
+ ### Search
49
+
50
+ ```bash
51
+ salai search <query> # Semantic product search (Hebrew)
52
+ --limit <n> # Max results (default 20)
53
+ --mode <fast|hybrid|ai> # Search mode
54
+ --store-scope <scope> # selected_only | retailer_wide | all_limited
55
+
56
+ salai autocomplete <query> # Fast autocomplete lookup
57
+ salai ac <query> # Alias
58
+ --limit <n> # Max results (default 15)
59
+ --method <text|semantic> # Search method (default text)
60
+ ```
61
+
62
+ ### Pricing
63
+
64
+ ```bash
65
+ salai prices <itemCode...> # Get prices for item codes
66
+ --stores <rid:sid,...> # Limit to specific stores
67
+
68
+ salai compare <code:qty...> # Compare across retailers
69
+ --stores <rid:sid,...> # Limit to specific stores
70
+
71
+ ```
72
+
73
+ ### Stores
74
+
75
+ ```bash
76
+ salai stores # List all online stores
77
+ salai retailers # List all retailers
78
+ salai store # Show selected store context
79
+ salai store set <rid> <sid> # Set your selected store
80
+ ```
81
+
82
+ ### Cart
83
+
84
+ ```bash
85
+ salai cart # Show your current cart
86
+ salai cart show --cart-id <id> # Show a specific cart
87
+
88
+ salai cart add <itemCode> # Add item to cart
89
+ --qty <n> # Quantity (default 1)
90
+ --cart-id <id> # Cart ID (auto-resolved if omitted)
91
+
92
+ salai cart set-qty <code> <qty> # Set quantity (0 = remove)
93
+ salai cart remove <itemCode> # Remove item
94
+ salai cart compare # Compare cart across stores
95
+ salai cart delete <cartId> # Delete a cart
96
+ ```
97
+
98
+ ### Recommendations
99
+
100
+ ```bash
101
+ salai recommend <itemCode> # Complementary product suggestions
102
+ salai rec <itemCode> # Alias
103
+ --limit <n> # Max results (default 5)
104
+ ```
105
+
106
+ ### Low-Level
107
+
108
+ ```bash
109
+ salai tools # List all available MCP tools
110
+ salai call <toolName> # Call any tool by name
111
+ --args '{"key": "value"}' # JSON arguments
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Pipe-Friendly
117
+
118
+ Every command supports `--json` for composable pipelines:
119
+
120
+ ```bash
121
+ salai search "חלב" --json | jq '.products[0].itemCode'
122
+ salai cart --json | jq '.items[].itemName'
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Environment Variables
128
+
129
+ | Variable | Description |
130
+ |---|---|
131
+ | `SALAI_API_KEY` | Your Salai API key from Profile |
132
+ | `SALAI_MCP_URL` | Override the MCP endpoint URL |
133
+
134
+ ---
135
+
136
+ ## How It Works
137
+
138
+ ```
139
+ Terminal / Script
140
+ │ salai search "חלב"
141
+
142
+ salai CLI (commander.js)
143
+ │ MCP callTool() over HTTPS
144
+
145
+ https://mcp.salai.co.il/mcp
146
+ ```
147
+
148
+ The CLI connects to the same Salai MCP HTTP endpoint used by the MCP bridge, using the same API key and accessing the same 18+ tools.
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ export declare function registerCallCommands(program: Command, getClient: () => Promise<Client>, isJson: () => boolean): void;
@@ -0,0 +1,44 @@
1
+ import { callTool } from '../mcpClient.js';
2
+ import { outputResult, outputRaw } from '../formatters/index.js';
3
+ export function registerCallCommands(program, getClient, isJson) {
4
+ program
5
+ .command('call <toolName>')
6
+ .description('Call any MCP tool by name (escape hatch)')
7
+ .option('--args <json>', 'JSON arguments', '{}')
8
+ .action(async (toolName, opts) => {
9
+ const client = await getClient();
10
+ let args;
11
+ try {
12
+ args = JSON.parse(opts.args);
13
+ }
14
+ catch {
15
+ console.error('Error: --args must be valid JSON');
16
+ process.exitCode = 1;
17
+ return;
18
+ }
19
+ const result = await callTool(client, toolName, args);
20
+ isJson() ? outputRaw(result) : outputResult(result, toolName);
21
+ await client.close();
22
+ });
23
+ program
24
+ .command('tools')
25
+ .description('List all available MCP tools')
26
+ .action(async () => {
27
+ const client = await getClient();
28
+ const { tools } = await client.listTools();
29
+ if (isJson()) {
30
+ console.log(JSON.stringify(tools, null, 2));
31
+ }
32
+ else {
33
+ const maxName = Math.max(...tools.map((t) => t.name.length));
34
+ for (const tool of tools) {
35
+ const name = tool.name.padEnd(maxName);
36
+ const desc = tool.description ?? '';
37
+ console.log(` ${name} ${desc}`);
38
+ }
39
+ console.log(`\n${tools.length} tool(s) available`);
40
+ }
41
+ await client.close();
42
+ });
43
+ }
44
+ //# sourceMappingURL=call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/commands/call.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,UAAU,oBAAoB,CAClC,OAAgB,EAChB,SAAgC,EAChC,MAAqB;IAErB,OAAO;SACJ,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,eAAe,EAAE,gBAAgB,EAAE,IAAI,CAAC;SAC/C,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,IAAI,IAA6B,CAAC;QAClC,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,8BAA8B,CAAC;SAC3C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QAE3C,IAAI,MAAM,EAAE,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACvC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;YACpC,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,oBAAoB,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ export declare function registerCartCommands(program: Command, getClient: () => Promise<Client>, isJson: () => boolean): void;
@@ -0,0 +1,116 @@
1
+ import { callTool, extractJson } from '../mcpClient.js';
2
+ import { outputResult, outputRaw } from '../formatters/index.js';
3
+ function parseStores(raw) {
4
+ if (!raw)
5
+ return undefined;
6
+ return raw.split(',').map((pair) => {
7
+ const [retailerId, storeId] = pair.split(':');
8
+ return { retailerId: retailerId, storeId: storeId };
9
+ });
10
+ }
11
+ async function resolveCartId(client, explicit) {
12
+ if (explicit)
13
+ return explicit;
14
+ const result = await callTool(client, 'get_my_cart');
15
+ const data = extractJson(result);
16
+ const id = data?.id ?? data?.cartId ?? data?.raw?.id ?? data?.raw?.cartId;
17
+ if (!id)
18
+ throw new Error('Could not resolve cart ID. Pass --cart-id explicitly.');
19
+ return id;
20
+ }
21
+ export function registerCartCommands(program, getClient, isJson) {
22
+ const cart = program.command('cart').description('Shopping cart operations');
23
+ cart
24
+ .command('show', { isDefault: true })
25
+ .description('Show current cart')
26
+ .option('--cart-id <id>', 'specific cart ID (default: your cart)')
27
+ .action(async (opts) => {
28
+ const client = await getClient();
29
+ let result;
30
+ if (opts.cartId) {
31
+ result = await callTool(client, 'get_cart', { cartId: opts.cartId });
32
+ isJson() ? outputRaw(result) : outputResult(result, 'get_cart');
33
+ }
34
+ else {
35
+ result = await callTool(client, 'get_my_cart');
36
+ isJson() ? outputRaw(result) : outputResult(result, 'get_my_cart');
37
+ }
38
+ await client.close();
39
+ });
40
+ cart
41
+ .command('add <itemCode>')
42
+ .description('Add item to cart')
43
+ .option('--qty <n>', 'quantity (default 1)')
44
+ .option('--cart-id <id>', 'cart ID (default: auto-resolve)')
45
+ .option('--name <name>', 'item name (optional)')
46
+ .action(async (itemCode, opts) => {
47
+ const client = await getClient();
48
+ const cartId = await resolveCartId(client, opts.cartId);
49
+ const args = {
50
+ cartId,
51
+ itemCode,
52
+ quantity: Number(opts.qty || 1),
53
+ };
54
+ if (opts.name)
55
+ args.itemName = opts.name;
56
+ const result = await callTool(client, 'add_cart_item', args);
57
+ isJson() ? outputRaw(result) : outputResult(result, 'add_cart_item');
58
+ await client.close();
59
+ });
60
+ cart
61
+ .command('set-qty <itemCode> <quantity>')
62
+ .description('Set item quantity (0 = remove)')
63
+ .option('--cart-id <id>', 'cart ID (default: auto-resolve)')
64
+ .action(async (itemCode, quantity, opts) => {
65
+ const client = await getClient();
66
+ const cartId = await resolveCartId(client, opts.cartId);
67
+ const result = await callTool(client, 'set_cart_item_quantity', {
68
+ cartId,
69
+ itemCode,
70
+ quantity: Number(quantity),
71
+ });
72
+ isJson() ? outputRaw(result) : outputResult(result, 'set_cart_item_quantity');
73
+ await client.close();
74
+ });
75
+ cart
76
+ .command('remove <itemCode>')
77
+ .description('Remove item from cart')
78
+ .option('--cart-id <id>', 'cart ID (default: auto-resolve)')
79
+ .action(async (itemCode, opts) => {
80
+ const client = await getClient();
81
+ const cartId = await resolveCartId(client, opts.cartId);
82
+ const result = await callTool(client, 'remove_cart_item', {
83
+ cartId,
84
+ itemCode,
85
+ });
86
+ isJson() ? outputRaw(result) : outputResult(result, 'remove_cart_item');
87
+ await client.close();
88
+ });
89
+ cart
90
+ .command('compare')
91
+ .description('Compare your cart across stores')
92
+ .option('--cart-id <id>', 'cart ID (optional)')
93
+ .option('--stores <pairs>', 'retailerId:storeId,... to limit scope')
94
+ .action(async (opts) => {
95
+ const client = await getClient();
96
+ const args = {};
97
+ if (opts.cartId)
98
+ args.cartId = opts.cartId;
99
+ const stores = parseStores(opts.stores);
100
+ if (stores)
101
+ args.stores = stores;
102
+ const result = await callTool(client, 'compare_my_cart', args);
103
+ isJson() ? outputRaw(result) : outputResult(result, 'compare_my_cart');
104
+ await client.close();
105
+ });
106
+ cart
107
+ .command('delete <cartId>')
108
+ .description('Delete a cart')
109
+ .action(async (cartId) => {
110
+ const client = await getClient();
111
+ const result = await callTool(client, 'delete_cart', { cartId });
112
+ isJson() ? outputRaw(result) : outputResult(result, 'delete_cart');
113
+ await client.close();
114
+ });
115
+ }
116
+ //# sourceMappingURL=cart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cart.js","sourceRoot":"","sources":["../../src/commands/cart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ export declare function registerPriceCommands(program: Command, getClient: () => Promise<Client>, isJson: () => boolean): void;
@@ -0,0 +1,45 @@
1
+ import { callTool } from '../mcpClient.js';
2
+ import { outputResult, outputRaw } from '../formatters/index.js';
3
+ function parseStores(raw) {
4
+ if (!raw)
5
+ return undefined;
6
+ return raw.split(',').map((pair) => {
7
+ const [retailerId, storeId] = pair.split(':');
8
+ return { retailerId: retailerId, storeId: storeId };
9
+ });
10
+ }
11
+ export function registerPriceCommands(program, getClient, isJson) {
12
+ program
13
+ .command('prices <itemCodes...>')
14
+ .description('Get prices for item codes')
15
+ .option('--stores <pairs>', 'retailerId:storeId,... to limit scope')
16
+ .action(async (itemCodes, opts) => {
17
+ const client = await getClient();
18
+ const args = { itemCodes };
19
+ const stores = parseStores(opts.stores);
20
+ if (stores)
21
+ args.stores = stores;
22
+ const result = await callTool(client, 'get_product_prices', args);
23
+ isJson() ? outputRaw(result) : outputResult(result, 'get_product_prices');
24
+ await client.close();
25
+ });
26
+ program
27
+ .command('compare <items...>')
28
+ .description('Compare prices across retailers (itemCode:qty ...)')
29
+ .option('--stores <pairs>', 'retailerId:storeId,... to limit scope')
30
+ .action(async (rawItems, opts) => {
31
+ const client = await getClient();
32
+ const items = rawItems.map((raw) => {
33
+ const [itemCode, qty] = raw.split(':');
34
+ return { itemCode: itemCode, quantity: Number(qty || 1) };
35
+ });
36
+ const args = { items };
37
+ const stores = parseStores(opts.stores);
38
+ if (stores)
39
+ args.stores = stores;
40
+ const result = await callTool(client, 'compare_prices', args);
41
+ isJson() ? outputRaw(result) : outputResult(result, 'compare_prices');
42
+ await client.close();
43
+ });
44
+ }
45
+ //# sourceMappingURL=prices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prices.js","sourceRoot":"","sources":["../../src/commands/prices.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACjC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9C,OAAO,EAAE,UAAU,EAAE,UAAW,EAAE,OAAO,EAAE,OAAQ,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAgB,EAChB,SAAgC,EAChC,MAAqB;IAErB,OAAO;SACJ,OAAO,CAAC,uBAAuB,CAAC;SAChC,WAAW,CAAC,2BAA2B,CAAC;SACxC,MAAM,CAAC,kBAAkB,EAAE,uCAAuC,CAAC;SACnE,MAAM,CAAC,KAAK,EAAE,SAAmB,EAAE,IAAI,EAAE,EAAE;QAC1C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAA4B,EAAE,SAAS,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAEjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,oBAAoB,EAAE,IAAI,CAAC,CAAC;QAClE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;QAC1E,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,oDAAoD,CAAC;SACjE,MAAM,CAAC,kBAAkB,EAAE,uCAAuC,CAAC;SACnE,MAAM,CAAC,KAAK,EAAE,QAAkB,EAAE,IAAI,EAAE,EAAE;QACzC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACjC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACvC,OAAO,EAAE,QAAQ,EAAE,QAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;QAC7D,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAEjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACtE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ export declare function registerRecommendCommands(program: Command, getClient: () => Promise<Client>, isJson: () => boolean): void;
@@ -0,0 +1,21 @@
1
+ import { callTool } from '../mcpClient.js';
2
+ import { outputResult, outputRaw } from '../formatters/index.js';
3
+ export function registerRecommendCommands(program, getClient, isJson) {
4
+ program
5
+ .command('recommend <itemCode>')
6
+ .alias('rec')
7
+ .description('Get complementary product recommendations')
8
+ .option('--limit <n>', 'max results (default 5)')
9
+ .action(async (itemCode, opts) => {
10
+ const client = await getClient();
11
+ const args = { itemCode };
12
+ if (opts.limit)
13
+ args.limit = Number(opts.limit);
14
+ const result = await callTool(client, 'get_complementary_recommendations', args);
15
+ isJson()
16
+ ? outputRaw(result)
17
+ : outputResult(result, 'get_complementary_recommendations');
18
+ await client.close();
19
+ });
20
+ }
21
+ //# sourceMappingURL=recommend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend.js","sourceRoot":"","sources":["../../src/commands/recommend.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,UAAU,yBAAyB,CACvC,OAAgB,EAChB,SAAgC,EAChC,MAAqB;IAErB,OAAO;SACJ,OAAO,CAAC,sBAAsB,CAAC;SAC/B,KAAK,CAAC,KAAK,CAAC;SACZ,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,aAAa,EAAE,yBAAyB,CAAC;SAChD,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAA4B,EAAE,QAAQ,EAAE,CAAC;QACnD,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,mCAAmC,EAAE,IAAI,CAAC,CAAC;QACjF,MAAM,EAAE;YACN,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;YACnB,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,mCAAmC,CAAC,CAAC;QAC9D,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ export declare function registerSearchCommands(program: Command, getClient: () => Promise<Client>, isJson: () => boolean): void;
@@ -0,0 +1,50 @@
1
+ import { callTool } from '../mcpClient.js';
2
+ import { outputResult, outputRaw } from '../formatters/index.js';
3
+ export function registerSearchCommands(program, getClient, isJson) {
4
+ program
5
+ .command('search <query>')
6
+ .description('Search products by Hebrew query')
7
+ .option('--limit <n>', 'max results (default 20)')
8
+ .option('--mode <mode>', 'fast | hybrid | ai')
9
+ .option('--store-scope <scope>', 'selected_only | retailer_wide | all_limited')
10
+ .option('--retailer <id>', 'filter by retailer ID')
11
+ .option('--store <id>', 'filter by store ID')
12
+ .action(async (query, opts) => {
13
+ const client = await getClient();
14
+ const args = { query };
15
+ if (opts.limit)
16
+ args.limit = Number(opts.limit);
17
+ if (opts.mode)
18
+ args.mode = opts.mode;
19
+ if (opts.storeScope)
20
+ args.storeScope = opts.storeScope;
21
+ if (opts.retailer)
22
+ args.retailerId = opts.retailer;
23
+ if (opts.store)
24
+ args.storeId = opts.store;
25
+ const result = await callTool(client, 'search_products', args);
26
+ isJson() ? outputRaw(result) : outputResult(result, 'search_products');
27
+ await client.close();
28
+ });
29
+ program
30
+ .command('autocomplete <query>')
31
+ .alias('ac')
32
+ .description('Fast autocomplete product lookup')
33
+ .option('--limit <n>', 'max results (default 15)')
34
+ .option('--method <m>', 'text | semantic (default text)')
35
+ .option('--store-scope <scope>', 'selected_only | retailer_wide | all_limited')
36
+ .action(async (query, opts) => {
37
+ const client = await getClient();
38
+ const args = { query };
39
+ if (opts.limit)
40
+ args.limit = Number(opts.limit);
41
+ if (opts.method)
42
+ args.method = opts.method;
43
+ if (opts.storeScope)
44
+ args.storeScope = opts.storeScope;
45
+ const result = await callTool(client, 'autocomplete_products', args);
46
+ isJson() ? outputRaw(result) : outputResult(result, 'autocomplete_products');
47
+ await client.close();
48
+ });
49
+ }
50
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,UAAU,sBAAsB,CACpC,OAAgB,EAChB,SAAgC,EAChC,MAAqB;IAErB,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,iCAAiC,CAAC;SAC9C,MAAM,CAAC,aAAa,EAAE,0BAA0B,CAAC;SACjD,MAAM,CAAC,eAAe,EAAE,oBAAoB,CAAC;SAC7C,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,CAAC;SAC9E,MAAM,CAAC,iBAAiB,EAAE,uBAAuB,CAAC;SAClD,MAAM,CAAC,cAAc,EAAE,oBAAoB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAI,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,CAAC;QAChD,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrC,IAAI,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACvD,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC;QACnD,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;QAE1C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,iBAAiB,EAAE,IAAI,CAAC,CAAC;QAC/D,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;QACvE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,sBAAsB,CAAC;SAC/B,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,aAAa,EAAE,0BAA0B,CAAC;SACjD,MAAM,CAAC,cAAc,EAAE,gCAAgC,CAAC;SACxD,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,CAAC;SAC9E,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAI,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,CAAC;QAChD,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3C,IAAI,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAEvD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,uBAAuB,EAAE,IAAI,CAAC,CAAC;QACrE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;QAC7E,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ export declare function registerStoreCommands(program: Command, getClient: () => Promise<Client>, isJson: () => boolean): void;
@@ -0,0 +1,45 @@
1
+ import { callTool } from '../mcpClient.js';
2
+ import { outputResult, outputRaw } from '../formatters/index.js';
3
+ export function registerStoreCommands(program, getClient, isJson) {
4
+ program
5
+ .command('stores')
6
+ .description('List all online stores (one per retailer)')
7
+ .action(async () => {
8
+ const client = await getClient();
9
+ const result = await callTool(client, 'get_stores');
10
+ isJson() ? outputRaw(result) : outputResult(result, 'get_stores');
11
+ await client.close();
12
+ });
13
+ program
14
+ .command('retailers')
15
+ .description('List all retailers')
16
+ .action(async () => {
17
+ const client = await getClient();
18
+ const result = await callTool(client, 'get_retailers');
19
+ isJson() ? outputRaw(result) : outputResult(result, 'get_retailers');
20
+ await client.close();
21
+ });
22
+ const store = program.command('store').description('Store context management');
23
+ store
24
+ .command('show', { isDefault: true })
25
+ .description('Show current selected store context')
26
+ .action(async () => {
27
+ const client = await getClient();
28
+ const result = await callTool(client, 'get_my_store_context');
29
+ isJson() ? outputRaw(result) : outputResult(result, 'get_my_store_context');
30
+ await client.close();
31
+ });
32
+ store
33
+ .command('set <retailerId> <storeId>')
34
+ .description('Set selected store')
35
+ .action(async (retailerId, storeId) => {
36
+ const client = await getClient();
37
+ const result = await callTool(client, 'set_my_selected_store', {
38
+ retailerId,
39
+ storeId,
40
+ });
41
+ isJson() ? outputRaw(result) : outputResult(result, 'set_my_selected_store');
42
+ await client.close();
43
+ });
44
+ }
45
+ //# sourceMappingURL=stores.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stores.js","sourceRoot":"","sources":["../../src/commands/stores.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,UAAU,qBAAqB,CACnC,OAAgB,EAChB,SAAgC,EAChC,MAAqB;IAErB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACpD,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAClE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QACvD,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QACrE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEL,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;IAE/E,KAAK;SACF,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACpC,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;QAC5E,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,4BAA4B,CAAC;SACrC,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,OAAe,EAAE,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,uBAAuB,EAAE;YAC7D,UAAU;YACV,OAAO;SACR,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;QAC7E,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Output formatting for the Salai CLI.
3
+ * Renders MCP tool results as human-friendly tables or raw JSON.
4
+ */
5
+ import type { ToolResult } from '../mcpClient.js';
6
+ export declare function outputRaw(result: ToolResult): void;
7
+ export declare function outputResult(result: ToolResult, toolName: string): void;
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Output formatting for the Salai CLI.
3
+ * Renders MCP tool results as human-friendly tables or raw JSON.
4
+ */
5
+ import { extractJson, extractText } from '../mcpClient.js';
6
+ // ── Helpers ──
7
+ const RESET = '\x1b[0m';
8
+ const BOLD = '\x1b[1m';
9
+ const DIM = '\x1b[2m';
10
+ const GREEN = '\x1b[32m';
11
+ const YELLOW = '\x1b[33m';
12
+ const CYAN = '\x1b[36m';
13
+ const RED = '\x1b[31m';
14
+ function c(color, text) {
15
+ return `${color}${text}${RESET}`;
16
+ }
17
+ function pad(str, len) {
18
+ const visible = str.replace(/\x1b\[[0-9;]*m/g, '');
19
+ return str + ' '.repeat(Math.max(0, len - visible.length));
20
+ }
21
+ function padR(str, len) {
22
+ const visible = str.replace(/\x1b\[[0-9;]*m/g, '');
23
+ return ' '.repeat(Math.max(0, len - visible.length)) + str;
24
+ }
25
+ function table(headers, rows, colAligns) {
26
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').replace(/\x1b\[[0-9;]*m/g, '').length)));
27
+ const aligns = colAligns ?? headers.map(() => 'l');
28
+ const sep = widths.map((w) => '─'.repeat(w + 2)).join('┼');
29
+ const formatRow = (cols) => cols
30
+ .map((col, i) => aligns[i] === 'r'
31
+ ? ' ' + padR(col, widths[i]) + ' '
32
+ : ' ' + pad(col, widths[i]) + ' ')
33
+ .join('│');
34
+ const lines = [];
35
+ lines.push(formatRow(headers.map((h) => c(BOLD, h))));
36
+ lines.push(sep);
37
+ for (const row of rows) {
38
+ lines.push(formatRow(row));
39
+ }
40
+ return lines.join('\n');
41
+ }
42
+ function shekel(n) {
43
+ if (n == null)
44
+ return c(DIM, '—');
45
+ return `₪${n.toFixed(2)}`;
46
+ }
47
+ const RLM = '\u200F';
48
+ /** Wrap Hebrew text with RTL mark so terminals render it correctly in padded columns. */
49
+ function rtl(text) {
50
+ if (!text)
51
+ return text;
52
+ if (/[\u0590-\u05FF]/.test(text))
53
+ return RLM + text + RLM;
54
+ return text;
55
+ }
56
+ // ── Public API ──
57
+ export function outputRaw(result) {
58
+ const json = extractJson(result);
59
+ console.log(JSON.stringify(json ?? result, null, 2));
60
+ }
61
+ export function outputResult(result, toolName) {
62
+ if (result.isError) {
63
+ const text = extractText(result);
64
+ console.error(c(RED, `Error: ${text ?? 'Unknown error'}`));
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ const data = extractJson(result);
69
+ if (!data) {
70
+ const text = extractText(result);
71
+ if (text) {
72
+ console.log(text);
73
+ }
74
+ else {
75
+ console.log(JSON.stringify(result, null, 2));
76
+ }
77
+ return;
78
+ }
79
+ switch (toolName) {
80
+ case 'search_products':
81
+ formatSearchProducts(data);
82
+ break;
83
+ case 'autocomplete_products':
84
+ formatAutocomplete(data);
85
+ break;
86
+ case 'get_product_prices':
87
+ formatProductPrices(data);
88
+ break;
89
+ case 'compare_prices':
90
+ formatComparePrices(data);
91
+ break;
92
+ case 'get_stores':
93
+ formatStores(data);
94
+ break;
95
+ case 'get_retailers':
96
+ formatRetailers(data);
97
+ break;
98
+ case 'get_my_store_context':
99
+ formatStoreContext(data);
100
+ break;
101
+ case 'set_my_selected_store':
102
+ formatStoreContext(data);
103
+ break;
104
+ case 'get_my_cart':
105
+ case 'get_cart':
106
+ formatCart(data);
107
+ break;
108
+ case 'add_cart_item':
109
+ case 'set_cart_item_quantity':
110
+ case 'remove_cart_item':
111
+ formatCartMutation(data, toolName);
112
+ break;
113
+ case 'compare_my_cart':
114
+ formatCartComparison(data);
115
+ break;
116
+ case 'delete_cart':
117
+ console.log(c(GREEN, '✓ Cart deleted'));
118
+ break;
119
+ case 'get_complementary_recommendations':
120
+ formatRecommendations(data);
121
+ break;
122
+ default:
123
+ console.log(JSON.stringify(data, null, 2));
124
+ }
125
+ }
126
+ // ── Tool-specific formatters ──
127
+ function formatSearchProducts(data) {
128
+ // structuredContent: { numberedProducts: [{ itemCode, itemName, price }] }
129
+ if (Array.isArray(data.numberedProducts)) {
130
+ const products = data.numberedProducts;
131
+ if (products.length === 0) {
132
+ console.log(c(DIM, 'No products found.'));
133
+ return;
134
+ }
135
+ if (data.query)
136
+ console.log(c(DIM, `Search: "${data.query}"\n`));
137
+ const rows = products.map((p) => [
138
+ p.itemCode ?? '',
139
+ rtl(p.itemName ?? ''),
140
+ p.displayPrice ?? shekel(p.price),
141
+ ]);
142
+ console.log(table(['Code', 'Name', 'Price'], rows, ['l', 'l', 'r']));
143
+ console.log(c(DIM, `\n${products.length} result(s)`));
144
+ return;
145
+ }
146
+ // Raw JSON: { recommendations: [{ product: {...}, bestPrice: {...} }] }
147
+ const recs = data.recommendations;
148
+ if (Array.isArray(recs)) {
149
+ if (recs.length === 0) {
150
+ console.log(c(DIM, 'No products found.'));
151
+ return;
152
+ }
153
+ if (data.query)
154
+ console.log(c(DIM, `Search: "${data.query}"\n`));
155
+ const rows = recs.map((rec) => {
156
+ const p = rec.product ?? {};
157
+ return [
158
+ p.itemCode ?? '',
159
+ rtl(p.manufactureItemDescription ?? p.itemName ?? ''),
160
+ shekel(rec.bestPrice?.price),
161
+ ];
162
+ });
163
+ console.log(table(['Code', 'Name', 'Price'], rows, ['l', 'l', 'r']));
164
+ console.log(c(DIM, `\n${recs.length} result(s)`));
165
+ return;
166
+ }
167
+ // Fallback: flat array
168
+ const products = data.products ?? data.results ?? data;
169
+ if (Array.isArray(products) && products.length > 0) {
170
+ const rows = products.map((p) => [
171
+ p.itemCode ?? '',
172
+ rtl(p.itemName ?? p.name ?? ''),
173
+ shekel(p.price ?? p.itemPrice),
174
+ ]);
175
+ console.log(table(['Code', 'Name', 'Price'], rows, ['l', 'l', 'r']));
176
+ console.log(c(DIM, `\n${products.length} result(s)`));
177
+ return;
178
+ }
179
+ console.log(c(DIM, 'No products found.'));
180
+ }
181
+ function formatAutocomplete(data) {
182
+ // structuredContent: { numberedProducts: [...] }
183
+ if (Array.isArray(data.numberedProducts)) {
184
+ const products = data.numberedProducts;
185
+ if (products.length === 0) {
186
+ console.log(c(DIM, 'No suggestions.'));
187
+ return;
188
+ }
189
+ const rows = products.map((p) => [
190
+ p.itemCode ?? '',
191
+ rtl(p.itemName ?? ''),
192
+ p.displayPrice ?? shekel(p.price),
193
+ ]);
194
+ console.log(table(['Code', 'Name', 'Price'], rows, ['l', 'l', 'r']));
195
+ return;
196
+ }
197
+ // Raw JSON: flat array [{ itemCode, itemName, bestPrice }]
198
+ const products = Array.isArray(data) ? data : (data.products ?? data.suggestions ?? []);
199
+ if (!Array.isArray(products) || products.length === 0) {
200
+ console.log(c(DIM, 'No suggestions.'));
201
+ return;
202
+ }
203
+ const rows = products.map((p) => [
204
+ p.itemCode ?? '',
205
+ rtl(p.itemName ?? p.name ?? ''),
206
+ shekel(p.bestPrice ?? p.price ?? p.itemPrice),
207
+ ]);
208
+ console.log(table(['Code', 'Name', 'Price'], rows, ['l', 'l', 'r']));
209
+ }
210
+ function formatProductPrices(data) {
211
+ const items = data.prices ?? data.items ?? data;
212
+ if (!Array.isArray(items) || items.length === 0) {
213
+ console.log(c(DIM, 'No price data.'));
214
+ return;
215
+ }
216
+ const rows = items.map((p) => [
217
+ p.itemCode ?? '',
218
+ rtl(p.itemName ?? ''),
219
+ shekel(p.price ?? p.itemPrice),
220
+ rtl(p.retailerName ?? p.retailerId ?? ''),
221
+ rtl(p.storeName ?? p.storeId ?? ''),
222
+ ]);
223
+ console.log(table(['Code', 'Name', 'Price', 'Retailer', 'Store'], rows, ['l', 'l', 'r', 'l', 'l']));
224
+ }
225
+ function formatComparePrices(data) {
226
+ // structuredContent: { viewType: 'store_comparison', stores: [...], summary: {...} }
227
+ if (data.viewType === 'store_comparison' && Array.isArray(data.stores)) {
228
+ const stores = data.stores;
229
+ if (stores.length === 0) {
230
+ console.log(c(DIM, 'No comparison data.'));
231
+ return;
232
+ }
233
+ const rows = stores.map((s) => {
234
+ const missing = s.availabilitySummary?.missingCount ?? 0;
235
+ const cheapest = s.isCheapest ? c(GREEN, ' ★') : '';
236
+ return [
237
+ rtl(s.storeLabel ?? s.retailerName ?? s.retailerId ?? ''),
238
+ s.displaySubtotal ?? shekel(s.subtotal),
239
+ String(missing),
240
+ cheapest,
241
+ ];
242
+ });
243
+ console.log(table(['Store', 'Total', 'Missing', ''], rows, ['l', 'r', 'r', 'l']));
244
+ if (data.summary?.cheapestStoreLabel) {
245
+ console.log(`\n${c(GREEN, '★')} Cheapest: ${c(BOLD, data.summary.cheapestStoreLabel)}`);
246
+ }
247
+ return;
248
+ }
249
+ // Raw JSON: { comparison: { retailers: [...] } } or { retailers: [...] }
250
+ const comparePayload = data.comparison ?? data;
251
+ const retailers = comparePayload.retailers ?? data.stores ?? data;
252
+ if (!Array.isArray(retailers) || retailers.length === 0) {
253
+ console.log(c(DIM, 'No comparison data.'));
254
+ return;
255
+ }
256
+ const rows = retailers.map((s) => {
257
+ const total = s.subtotal ?? s.total ?? s.totalPrice ?? s.basketTotal;
258
+ const missing = (s.items ?? []).filter((i) => !i.available).length;
259
+ return [
260
+ rtl(s.retailerName ?? s.retailerId ?? ''),
261
+ shekel(total),
262
+ String(missing),
263
+ ];
264
+ });
265
+ console.log(table(['Retailer', 'Total', 'Missing'], rows, ['l', 'r', 'r']));
266
+ }
267
+ function formatStores(data) {
268
+ const stores = data.stores ?? data;
269
+ if (!Array.isArray(stores) || stores.length === 0) {
270
+ console.log(c(DIM, 'No stores.'));
271
+ return;
272
+ }
273
+ const rows = stores.map((s) => [
274
+ s.retailerId ?? '',
275
+ s.storeId ?? '',
276
+ rtl(s.retailerName ?? ''),
277
+ rtl(s.storeName ?? s.name ?? ''),
278
+ ]);
279
+ console.log(table(['Retailer ID', 'Store ID', 'Retailer', 'Store'], rows));
280
+ }
281
+ function formatRetailers(data) {
282
+ const retailers = data.retailers ?? data;
283
+ if (!Array.isArray(retailers) || retailers.length === 0) {
284
+ console.log(c(DIM, 'No retailers.'));
285
+ return;
286
+ }
287
+ const rows = retailers.map((r) => [
288
+ r.id ?? r.retailerId ?? '',
289
+ rtl(r.name ?? r.displayName ?? ''),
290
+ ]);
291
+ console.log(table(['ID', 'Name'], rows));
292
+ }
293
+ function formatStoreContext(data) {
294
+ const sel = data.selectedStore ?? data;
295
+ if (sel?.retailerName || sel?.retailerId) {
296
+ console.log(`${c(BOLD, 'Selected store:')} ${rtl(sel.retailerName ?? sel.retailerId)} — ${rtl(sel.storeName ?? sel.storeId ?? '')}`);
297
+ }
298
+ else {
299
+ console.log(c(YELLOW, 'No store selected. Use: salai store set <retailerId> <storeId>'));
300
+ }
301
+ if (data.activeStores && Array.isArray(data.activeStores)) {
302
+ console.log(c(DIM, `\n${data.activeStores.length} active store(s) available`));
303
+ }
304
+ }
305
+ function formatCart(data) {
306
+ // structuredContent: { viewType: 'cart_overview', items: [...], summary: {...} }
307
+ if (data.viewType === 'cart_overview') {
308
+ const summary = data.summary ?? {};
309
+ console.log(`${c(BOLD, 'Cart')} ${c(DIM, '—')} ${rtl(summary.storeLabel ?? '')}`);
310
+ const items = data.items ?? [];
311
+ if (!Array.isArray(items) || items.length === 0) {
312
+ console.log(c(DIM, 'Cart is empty.'));
313
+ return;
314
+ }
315
+ const rows = items.map((it) => [
316
+ it.itemCode ?? '',
317
+ rtl(it.itemName ?? ''),
318
+ String(it.quantity ?? 1),
319
+ it.displayPrice ?? shekel(it.unitPrice),
320
+ it.displaySubtotal ?? shekel(it.subtotal),
321
+ ]);
322
+ console.log(table(['Code', 'Name', 'Qty', 'Unit', 'Subtotal'], rows, ['l', 'l', 'r', 'r', 'r']));
323
+ console.log(`\n${c(BOLD, 'Total:')} ${c(GREEN, summary.displayGrandTotal ?? shekel(summary.grandTotal))}`);
324
+ return;
325
+ }
326
+ // Raw JSON fallback
327
+ const cartId = data.id ?? data.cartId ?? '';
328
+ const items = data.items ?? data.itemsWithPrices ?? data.storeCarts?.[0]?.items ?? [];
329
+ console.log(`${c(BOLD, 'Cart:')} ${c(DIM, cartId)}`);
330
+ if (!Array.isArray(items) || items.length === 0) {
331
+ console.log(c(DIM, 'Cart is empty.'));
332
+ return;
333
+ }
334
+ const rows = items.map((entry) => {
335
+ const it = entry.item ?? entry;
336
+ const price = entry.productPrice?.itemPrice ?? it.price ?? it.itemPrice;
337
+ const qty = it.quantity ?? 1;
338
+ return [
339
+ it.itemCode ?? '',
340
+ rtl(it.itemName ?? it.name ?? ''),
341
+ String(qty),
342
+ shekel(price),
343
+ shekel(entry.subtotal ?? (price != null ? price * qty : null)),
344
+ ];
345
+ });
346
+ console.log(table(['Code', 'Name', 'Qty', 'Unit', 'Subtotal'], rows, ['l', 'l', 'r', 'r', 'r']));
347
+ const total = data.grandTotal ?? data.total ?? data.totalPrice;
348
+ if (total != null) {
349
+ console.log(`\n${c(BOLD, 'Total:')} ${c(GREEN, shekel(total))}`);
350
+ }
351
+ }
352
+ function formatCartMutation(data, tool) {
353
+ // structuredContent: cart_overview after mutation
354
+ if (data.viewType === 'cart_overview') {
355
+ const verb = tool === 'add_cart_item' ? 'Added to' : tool === 'remove_cart_item' ? 'Removed from' : 'Updated';
356
+ console.log(`${c(GREEN, '✓')} ${verb} cart`);
357
+ formatCart(data);
358
+ return;
359
+ }
360
+ const verb = tool === 'add_cart_item'
361
+ ? 'Added'
362
+ : tool === 'remove_cart_item'
363
+ ? 'Removed'
364
+ : 'Updated';
365
+ const addResult = data._addItemResult ?? data;
366
+ const itemAdded = addResult.itemAdded ?? addResult.item ?? addResult;
367
+ const name = itemAdded?.itemName ?? itemAdded?.itemCode ?? '';
368
+ console.log(`${c(GREEN, '✓')} ${verb} ${c(BOLD, rtl(name))}`);
369
+ if (addResult.notAvailable) {
370
+ console.log(c(YELLOW, '⚠ Item is not available at selected store'));
371
+ }
372
+ if (data.itemsWithPrices || data.items || data.cart) {
373
+ formatCart(data.cart ?? data);
374
+ }
375
+ }
376
+ function formatCartComparison(data) {
377
+ formatComparePrices(data);
378
+ }
379
+ function formatRecommendations(data) {
380
+ const recs = data.recommendations ?? data.products ?? data;
381
+ if (!Array.isArray(recs) || recs.length === 0) {
382
+ console.log(c(DIM, 'No recommendations.'));
383
+ return;
384
+ }
385
+ const rows = recs.map((r) => [
386
+ r.itemCode ?? '',
387
+ rtl(r.itemName ?? r.name ?? ''),
388
+ shekel(r.price ?? r.itemPrice),
389
+ ]);
390
+ console.log(table(['Code', 'Name', 'Price'], rows, ['l', 'l', 'r']));
391
+ }
392
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared MCP client factory.
3
+ * Connects to the Salai MCP HTTP endpoint and provides tool-calling helpers.
4
+ */
5
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
6
+ export declare const DEFAULT_MCP_URL = "https://mcp.salai.co.il/mcp";
7
+ export declare const PACKAGE_VERSION = "0.1.0";
8
+ export interface McpClientOptions {
9
+ apiKey: string | null;
10
+ url: string;
11
+ clientName?: string;
12
+ }
13
+ export declare function resolveConfig(overrides?: {
14
+ apiKey?: string;
15
+ url?: string;
16
+ }): {
17
+ apiKey: string | null;
18
+ url: string;
19
+ };
20
+ export declare function buildHeaders(apiKey: string | null): Record<string, string>;
21
+ export declare function createClient(opts: McpClientOptions): Promise<Client>;
22
+ export interface ToolResult {
23
+ content?: Array<{
24
+ type: string;
25
+ text?: string;
26
+ [k: string]: unknown;
27
+ }>;
28
+ structuredContent?: unknown;
29
+ isError?: boolean;
30
+ [k: string]: unknown;
31
+ }
32
+ export declare function callTool(client: Client, name: string, args?: Record<string, unknown>): Promise<ToolResult>;
33
+ /** Extract the first text content block from an MCP tool result. */
34
+ export declare function extractText(result: ToolResult): string | null;
35
+ /**
36
+ * Extract parsed JSON from an MCP tool result.
37
+ * Prefers structuredContent, then tries each text block for valid JSON.
38
+ */
39
+ export declare function extractJson(result: ToolResult): unknown;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Shared MCP client factory.
3
+ * Connects to the Salai MCP HTTP endpoint and provides tool-calling helpers.
4
+ */
5
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
6
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
7
+ export const DEFAULT_MCP_URL = 'https://mcp.salai.co.il/mcp';
8
+ export const PACKAGE_VERSION = '0.1.0';
9
+ export function resolveConfig(overrides) {
10
+ return {
11
+ apiKey: overrides?.apiKey ||
12
+ process.env.SALAI_API_KEY ||
13
+ process.env.MCP_API_KEY ||
14
+ null,
15
+ url: overrides?.url || process.env.SALAI_MCP_URL || DEFAULT_MCP_URL,
16
+ };
17
+ }
18
+ export function buildHeaders(apiKey) {
19
+ const headers = {
20
+ 'Content-Type': 'application/json',
21
+ };
22
+ if (apiKey) {
23
+ headers['Authorization'] = `Bearer ${apiKey}`;
24
+ }
25
+ return headers;
26
+ }
27
+ export async function createClient(opts) {
28
+ const headers = buildHeaders(opts.apiKey);
29
+ const transport = new StreamableHTTPClientTransport(new URL(opts.url), {
30
+ requestInit: { headers },
31
+ });
32
+ const client = new Client({ name: opts.clientName ?? 'salai-cli', version: PACKAGE_VERSION }, { capabilities: {} });
33
+ await client.connect(transport);
34
+ return client;
35
+ }
36
+ export async function callTool(client, name, args = {}) {
37
+ return (await client.callTool({ name, arguments: args }));
38
+ }
39
+ /** Extract the first text content block from an MCP tool result. */
40
+ export function extractText(result) {
41
+ if (!result.content)
42
+ return null;
43
+ const textBlock = result.content.find((c) => c.type === 'text');
44
+ return textBlock?.text ?? null;
45
+ }
46
+ /**
47
+ * Extract parsed JSON from an MCP tool result.
48
+ * Prefers structuredContent, then tries each text block for valid JSON.
49
+ */
50
+ export function extractJson(result) {
51
+ if (result.structuredContent != null) {
52
+ return result.structuredContent;
53
+ }
54
+ if (!result.content)
55
+ return null;
56
+ const textBlocks = result.content.filter((c) => c.type === 'text' && c.text);
57
+ for (const block of textBlocks) {
58
+ try {
59
+ return JSON.parse(block.text);
60
+ }
61
+ catch {
62
+ // not JSON, try next block
63
+ }
64
+ }
65
+ return textBlocks[0]?.text ?? null;
66
+ }
67
+ //# sourceMappingURL=mcpClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpClient.js","sourceRoot":"","sources":["../src/mcpClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Salai CLI — human-facing command-line interface for Salai grocery intelligence.
4
+ *
5
+ * Calls the Salai MCP server over HTTPS, same endpoint and auth as the MCP bridge.
6
+ *
7
+ * Usage:
8
+ * salai search "חלב"
9
+ * salai cart add 7290019489443 --qty 2
10
+ * salai compare 7290019489443:1 7290000123456:3
11
+ * salai tools
12
+ */
13
+ export {};
package/dist/salai.js ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Salai CLI — human-facing command-line interface for Salai grocery intelligence.
4
+ *
5
+ * Calls the Salai MCP server over HTTPS, same endpoint and auth as the MCP bridge.
6
+ *
7
+ * Usage:
8
+ * salai search "חלב"
9
+ * salai cart add 7290019489443 --qty 2
10
+ * salai compare 7290019489443:1 7290000123456:3
11
+ * salai tools
12
+ */
13
+ import { Command } from 'commander';
14
+ import { createClient, resolveConfig, PACKAGE_VERSION } from './mcpClient.js';
15
+ import { registerSearchCommands } from './commands/search.js';
16
+ import { registerPriceCommands } from './commands/prices.js';
17
+ import { registerStoreCommands } from './commands/stores.js';
18
+ import { registerCartCommands } from './commands/cart.js';
19
+ import { registerRecommendCommands } from './commands/recommend.js';
20
+ import { registerCallCommands } from './commands/call.js';
21
+ const program = new Command()
22
+ .name('salai')
23
+ .description('Salai grocery intelligence CLI')
24
+ .version(PACKAGE_VERSION, '-v, --version')
25
+ .option('-k, --api-key <key>', 'Salai API key (or SALAI_API_KEY env)')
26
+ .option('--url <url>', 'MCP endpoint URL (or SALAI_MCP_URL env)')
27
+ .option('--json', 'output raw JSON instead of formatted tables')
28
+ .configureOutput({
29
+ writeErr: (str) => process.stderr.write(str),
30
+ });
31
+ let _client = null;
32
+ async function getClient() {
33
+ if (_client)
34
+ return _client;
35
+ const opts = program.opts();
36
+ const config = resolveConfig({
37
+ apiKey: opts.apiKey,
38
+ url: opts.url,
39
+ });
40
+ if (!config.apiKey) {
41
+ console.error('Warning: No API key. Set SALAI_API_KEY or use --api-key.\n' +
42
+ 'Get your key: https://app.salai.co.il → Profile → API Key');
43
+ }
44
+ _client = await createClient({
45
+ ...config,
46
+ clientName: 'salai-cli',
47
+ });
48
+ return _client;
49
+ }
50
+ function isJson() {
51
+ return !!program.opts().json;
52
+ }
53
+ registerSearchCommands(program, getClient, isJson);
54
+ registerPriceCommands(program, getClient, isJson);
55
+ registerStoreCommands(program, getClient, isJson);
56
+ registerCartCommands(program, getClient, isJson);
57
+ registerRecommendCommands(program, getClient, isJson);
58
+ registerCallCommands(program, getClient, isJson);
59
+ program.exitOverride();
60
+ async function main() {
61
+ try {
62
+ await program.parseAsync(process.argv);
63
+ }
64
+ catch (err) {
65
+ const isCommanderExit = err && typeof err === 'object' && 'code' in err && err.code === 'commander.helpDisplayed';
66
+ if (isCommanderExit)
67
+ return;
68
+ const versionExit = err && typeof err === 'object' && 'code' in err && err.code === 'commander.version';
69
+ if (versionExit)
70
+ return;
71
+ const msg = err instanceof Error ? err.message : String(err);
72
+ console.error(`Error: ${msg}`);
73
+ process.exitCode = 1;
74
+ }
75
+ finally {
76
+ if (_client) {
77
+ await _client.close().catch(() => { });
78
+ }
79
+ }
80
+ }
81
+ main();
82
+ //# sourceMappingURL=salai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"salai.js","sourceRoot":"","sources":["../src/salai.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "salai",
3
+ "version": "0.1.0",
4
+ "description": "Salai grocery intelligence CLI — search products, compare prices, manage your cart from the terminal",
5
+ "keywords": ["salai", "grocery", "price-comparison", "cli", "israel"],
6
+ "homepage": "https://salai.co.il",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/Salai-app/salai-cli"
10
+ },
11
+ "license": "MIT",
12
+ "type": "module",
13
+ "bin": {
14
+ "salai": "dist/salai.js"
15
+ },
16
+ "main": "./dist/salai.js",
17
+ "files": [
18
+ "dist",
19
+ "!dist/**/*.test.*",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "dev": "tsx src/salai.ts",
26
+ "test": "tsc && node --test dist/salai.test.js",
27
+ "clean": "rm -rf dist",
28
+ "prepublishOnly": "pnpm run build"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.25.2",
32
+ "commander": "^13.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^20.8.0",
36
+ "tsx": "^4.4.0",
37
+ "typescript": "^5.2.2"
38
+ },
39
+ "engines": {
40
+ "node": ">=20.0.0"
41
+ }
42
+ }