@oda-agent/openclaw-plugin 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.
@@ -0,0 +1,3 @@
1
+ export { createOpenClawPlugin } from './plugin.js';
2
+ export type { ShoppingList, OrderHistorySummary, OpenClawPlugin } from './plugin.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOpenClawPlugin = void 0;
4
+ var plugin_js_1 = require("./plugin.js");
5
+ Object.defineProperty(exports, "createOpenClawPlugin", { enumerable: true, get: function () { return plugin_js_1.createOpenClawPlugin; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAAmD;AAA1C,iHAAA,oBAAoB,OAAA"}
@@ -0,0 +1,66 @@
1
+ import type { OdaClient, OdaProduct } from '@oda-agent/core';
2
+ /** A named shopping list with a list of product IDs and desired quantities. */
3
+ export interface ShoppingList {
4
+ name: string;
5
+ items: Array<{
6
+ productId: number;
7
+ quantity: number;
8
+ }>;
9
+ }
10
+ /** Summary of a user's order history. */
11
+ export interface OrderHistorySummary {
12
+ totalOrders: number;
13
+ totalSpend: string;
14
+ currency: string;
15
+ mostOrderedProducts: Array<{
16
+ product: OdaProduct;
17
+ timesOrdered: number;
18
+ }>;
19
+ }
20
+ /** The OpenClaw plugin object returned by the factory. */
21
+ export interface OpenClawPlugin {
22
+ /**
23
+ * Search for products and build a shopping list from a plain-text description.
24
+ * Returns a list of matched products ready to add to cart.
25
+ */
26
+ buildShoppingList(name: string, items: Array<{
27
+ query: string;
28
+ quantity: number;
29
+ }>): Promise<ShoppingList>;
30
+ /**
31
+ * Analyse the user's past orders and return a summary.
32
+ */
33
+ analyseOrderHistory(maxPages?: number): Promise<OrderHistorySummary>;
34
+ /**
35
+ * Prepare the cart from a shopping list — adds all items in one call.
36
+ */
37
+ prepareCart(list: ShoppingList): Promise<void>;
38
+ /**
39
+ * Find the cheapest available delivery slot.
40
+ * Returns undefined if no slots are available.
41
+ */
42
+ findCheapestDeliverySlot(): Promise<{
43
+ id: number;
44
+ start: string;
45
+ end: string;
46
+ price: string;
47
+ currency: string;
48
+ } | undefined>;
49
+ }
50
+ /**
51
+ * Create an OpenClaw plugin that wraps an authenticated OdaClient.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const client = new OdaClient({ credentials: { email, password } });
56
+ * await client.login();
57
+ * const plugin = createOpenClawPlugin(client);
58
+ * const list = await plugin.buildShoppingList('Weekly shop', [
59
+ * { query: 'oat milk', quantity: 2 },
60
+ * { query: 'sourdough bread', quantity: 1 },
61
+ * ]);
62
+ * await plugin.prepareCart(list);
63
+ * ```
64
+ */
65
+ export declare function createOpenClawPlugin(client: OdaClient): OpenClawPlugin;
66
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAmB,MAAM,iBAAiB,CAAC;AAM9E,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AAED,yCAAyC;AACzC,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3E;AAED,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAE1G;;OAEG;IACH,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAErE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;OAGG;IACH,wBAAwB,IAAI,OAAO,CACjC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CACxF,CAAC;CACH;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,cAAc,CAwEtE"}
package/dist/plugin.js ADDED
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOpenClawPlugin = void 0;
4
+ // ---------------------------------------------------------------------------
5
+ // Factory
6
+ // ---------------------------------------------------------------------------
7
+ /**
8
+ * Create an OpenClaw plugin that wraps an authenticated OdaClient.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const client = new OdaClient({ credentials: { email, password } });
13
+ * await client.login();
14
+ * const plugin = createOpenClawPlugin(client);
15
+ * const list = await plugin.buildShoppingList('Weekly shop', [
16
+ * { query: 'oat milk', quantity: 2 },
17
+ * { query: 'sourdough bread', quantity: 1 },
18
+ * ]);
19
+ * await plugin.prepareCart(list);
20
+ * ```
21
+ */
22
+ function createOpenClawPlugin(client) {
23
+ return {
24
+ async buildShoppingList(name, items) {
25
+ const resolved = [];
26
+ for (const item of items) {
27
+ const results = await client.searchProducts(item.query);
28
+ const first = results.results[0];
29
+ if (first) {
30
+ resolved.push({ productId: first.id, quantity: item.quantity });
31
+ }
32
+ }
33
+ return { name, items: resolved };
34
+ },
35
+ async analyseOrderHistory(maxPages = 5) {
36
+ const productCounts = new Map();
37
+ let totalOrders = 0;
38
+ let totalSpendCents = 0;
39
+ let currency = 'NOK';
40
+ for (let page = 1; page <= maxPages; page++) {
41
+ const orderPage = await client.getOrders(page);
42
+ if (orderPage.results.length === 0)
43
+ break;
44
+ totalOrders += orderPage.results.length;
45
+ for (const order of orderPage.results) {
46
+ currency = order.currency;
47
+ totalSpendCents += Math.round(parseFloat(order.total_price) * 100);
48
+ for (const item of order.items) {
49
+ const existing = productCounts.get(item.product.id);
50
+ if (existing) {
51
+ existing.count += item.quantity;
52
+ }
53
+ else {
54
+ productCounts.set(item.product.id, { product: item.product, count: item.quantity });
55
+ }
56
+ }
57
+ }
58
+ if (!orderPage.next)
59
+ break;
60
+ }
61
+ const sorted = [...productCounts.values()]
62
+ .sort((a, b) => b.count - a.count)
63
+ .slice(0, 10)
64
+ .map(({ product, count }) => ({ product, timesOrdered: count }));
65
+ return {
66
+ totalOrders,
67
+ totalSpend: (totalSpendCents / 100).toFixed(2),
68
+ currency,
69
+ mostOrderedProducts: sorted,
70
+ };
71
+ },
72
+ async prepareCart(list) {
73
+ for (const item of list.items) {
74
+ await client.addToCart(item.productId, item.quantity);
75
+ }
76
+ },
77
+ async findCheapestDeliverySlot() {
78
+ const slots = await client.getDeliverySlots();
79
+ const available = slots.filter((s) => s.is_available);
80
+ if (available.length === 0)
81
+ return undefined;
82
+ return available.sort((a, b) => parseFloat(a.price) - parseFloat(b.price))[0];
83
+ },
84
+ };
85
+ }
86
+ exports.createOpenClawPlugin = createOpenClawPlugin;
87
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Cart-mutation tools for the Oda shopping assistant.
3
+ *
4
+ * These tools are DISABLED by default and must be explicitly enabled by the
5
+ * user. Each tool mutates the shopping cart and therefore requires explicit
6
+ * user confirmation before it is invoked.
7
+ *
8
+ * Tools exposed:
9
+ * - addToCart — add a single product to the cart
10
+ * - removeFromCart — remove a cart item by its product ID (cart.items[].product.id)
11
+ * - clearCart — remove all items from the cart
12
+ * - prepareCart — bulk-add all items from a ShoppingList to the cart
13
+ *
14
+ * SAFETY NOTE: The assistant workflow must present a full summary of intended
15
+ * changes and receive unambiguous user approval before calling any tool in
16
+ * this module. See SKILL.md for the canonical workflow.
17
+ */
18
+ import type { OdaClient } from '@oda-agent/core';
19
+ import type { ShoppingList } from '../plugin.js';
20
+ /** Result of a cart mutation operation. */
21
+ export interface CartMutationResult {
22
+ /** Human-readable description of what changed. */
23
+ summary: string;
24
+ }
25
+ /**
26
+ * Add `quantity` units of `productId` to the cart.
27
+ *
28
+ * Requires explicit user confirmation before calling.
29
+ */
30
+ export declare function addToCart(client: OdaClient, productId: number, quantity: number): Promise<CartMutationResult>;
31
+ /**
32
+ * Remove a product from the cart by its product ID (`cart.items[].product.id`).
33
+ *
34
+ * Note: `productId` is the Oda product ID, NOT the cart line-item ID.
35
+ * The Oda API removes the item by setting its quantity to 0 via the product ID.
36
+ *
37
+ * Requires explicit user confirmation before calling.
38
+ */
39
+ export declare function removeFromCart(client: OdaClient, productId: number): Promise<CartMutationResult>;
40
+ /**
41
+ * Remove all items from the cart.
42
+ *
43
+ * Requires explicit user confirmation before calling.
44
+ */
45
+ export declare function clearCart(client: OdaClient): Promise<CartMutationResult>;
46
+ /**
47
+ * Add every item in `list` to the cart, sequentially one item at a time.
48
+ *
49
+ * Requires explicit user confirmation before calling. The caller should show
50
+ * the full shopping list to the user and wait for approval.
51
+ */
52
+ export declare function prepareCart(client: OdaClient, list: ShoppingList): Promise<CartMutationResult>;
53
+ //# sourceMappingURL=cartMutationTools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cartMutationTools.d.ts","sourceRoot":"","sources":["../../src/tools/cartMutationTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAMjD,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAG7B;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAG7B;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAG9E;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,kBAAkB,CAAC,CAO7B"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * Cart-mutation tools for the Oda shopping assistant.
4
+ *
5
+ * These tools are DISABLED by default and must be explicitly enabled by the
6
+ * user. Each tool mutates the shopping cart and therefore requires explicit
7
+ * user confirmation before it is invoked.
8
+ *
9
+ * Tools exposed:
10
+ * - addToCart — add a single product to the cart
11
+ * - removeFromCart — remove a cart item by its product ID (cart.items[].product.id)
12
+ * - clearCart — remove all items from the cart
13
+ * - prepareCart — bulk-add all items from a ShoppingList to the cart
14
+ *
15
+ * SAFETY NOTE: The assistant workflow must present a full summary of intended
16
+ * changes and receive unambiguous user approval before calling any tool in
17
+ * this module. See SKILL.md for the canonical workflow.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.prepareCart = exports.clearCart = exports.removeFromCart = exports.addToCart = void 0;
21
+ // ---------------------------------------------------------------------------
22
+ // Tool implementations
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * Add `quantity` units of `productId` to the cart.
26
+ *
27
+ * Requires explicit user confirmation before calling.
28
+ */
29
+ async function addToCart(client, productId, quantity) {
30
+ await client.addToCart(productId, quantity);
31
+ return { summary: `Added ${quantity}× product #${productId} to cart.` };
32
+ }
33
+ exports.addToCart = addToCart;
34
+ /**
35
+ * Remove a product from the cart by its product ID (`cart.items[].product.id`).
36
+ *
37
+ * Note: `productId` is the Oda product ID, NOT the cart line-item ID.
38
+ * The Oda API removes the item by setting its quantity to 0 via the product ID.
39
+ *
40
+ * Requires explicit user confirmation before calling.
41
+ */
42
+ async function removeFromCart(client, productId) {
43
+ await client.removeFromCart(productId);
44
+ return { summary: `Removed product #${productId} from cart.` };
45
+ }
46
+ exports.removeFromCart = removeFromCart;
47
+ /**
48
+ * Remove all items from the cart.
49
+ *
50
+ * Requires explicit user confirmation before calling.
51
+ */
52
+ async function clearCart(client) {
53
+ await client.clearCart();
54
+ return { summary: 'Cart cleared.' };
55
+ }
56
+ exports.clearCart = clearCart;
57
+ /**
58
+ * Add every item in `list` to the cart, sequentially one item at a time.
59
+ *
60
+ * Requires explicit user confirmation before calling. The caller should show
61
+ * the full shopping list to the user and wait for approval.
62
+ */
63
+ async function prepareCart(client, list) {
64
+ for (const item of list.items) {
65
+ await client.addToCart(item.productId, item.quantity);
66
+ }
67
+ return {
68
+ summary: `Added ${list.items.length} item(s) from list "${list.name}" to cart.`,
69
+ };
70
+ }
71
+ exports.prepareCart = prepareCart;
72
+ //# sourceMappingURL=cartMutationTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cartMutationTools.js","sourceRoot":"","sources":["../../src/tools/cartMutationTools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;AAeH,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E;;;;GAIG;AACI,KAAK,UAAU,SAAS,CAC7B,MAAiB,EACjB,SAAiB,EACjB,QAAgB;IAEhB,MAAM,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,OAAO,EAAE,SAAS,QAAQ,cAAc,SAAS,WAAW,EAAE,CAAC;AAC1E,CAAC;AAPD,8BAOC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,cAAc,CAClC,MAAiB,EACjB,SAAiB;IAEjB,MAAM,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,EAAE,OAAO,EAAE,oBAAoB,SAAS,aAAa,EAAE,CAAC;AACjE,CAAC;AAND,wCAMC;AAED;;;;GAIG;AACI,KAAK,UAAU,SAAS,CAAC,MAAiB;IAC/C,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IACzB,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;AACtC,CAAC;AAHD,8BAGC;AAED;;;;;GAKG;AACI,KAAK,UAAU,WAAW,CAC/B,MAAiB,EACjB,IAAkB;IAElB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IACD,OAAO;QACL,OAAO,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,uBAAuB,IAAI,CAAC,IAAI,YAAY;KAChF,CAAC;AACJ,CAAC;AAVD,kCAUC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * High-risk tools — ORDER PLACEMENT IS OUT OF SCOPE FOR v0.
3
+ *
4
+ * This module documents the high-risk tool surface for the Oda shopping
5
+ * assistant. None of the tools in this module are implemented. They exist
6
+ * solely to make the safety boundary explicit and to reserve the correct
7
+ * API surface for a future version.
8
+ *
9
+ * Rationale
10
+ * ---------
11
+ * Placing a grocery order involves real financial transactions. Doing so
12
+ * automatically, without strong human oversight and a confirmed payment
13
+ * step, would be unsafe. The v0 assistant is therefore read-and-plan-only,
14
+ * with cart mutations being the furthest extent of automation.
15
+ *
16
+ * Future work
17
+ * -----------
18
+ * A future version may expose a `placeOrder` tool behind:
19
+ * 1. An explicit double-confirmation flow (show full order summary + price).
20
+ * 2. A separate opt-in feature flag in openclaw.plugin.json.
21
+ * 3. A mandatory audit-log entry before and after placement.
22
+ *
23
+ * Do NOT implement payment logic or final order placement in this package.
24
+ */
25
+ /**
26
+ * @throws Always throws — order placement is not implemented in v0.
27
+ *
28
+ * @deprecated Not implemented. See module-level documentation.
29
+ */
30
+ export declare function placeOrder(): never;
31
+ //# sourceMappingURL=highRiskTools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highRiskTools.d.ts","sourceRoot":"","sources":["../../src/tools/highRiskTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,KAAK,CAMlC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * High-risk tools — ORDER PLACEMENT IS OUT OF SCOPE FOR v0.
4
+ *
5
+ * This module documents the high-risk tool surface for the Oda shopping
6
+ * assistant. None of the tools in this module are implemented. They exist
7
+ * solely to make the safety boundary explicit and to reserve the correct
8
+ * API surface for a future version.
9
+ *
10
+ * Rationale
11
+ * ---------
12
+ * Placing a grocery order involves real financial transactions. Doing so
13
+ * automatically, without strong human oversight and a confirmed payment
14
+ * step, would be unsafe. The v0 assistant is therefore read-and-plan-only,
15
+ * with cart mutations being the furthest extent of automation.
16
+ *
17
+ * Future work
18
+ * -----------
19
+ * A future version may expose a `placeOrder` tool behind:
20
+ * 1. An explicit double-confirmation flow (show full order summary + price).
21
+ * 2. A separate opt-in feature flag in openclaw.plugin.json.
22
+ * 3. A mandatory audit-log entry before and after placement.
23
+ *
24
+ * Do NOT implement payment logic or final order placement in this package.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.placeOrder = void 0;
28
+ // ---------------------------------------------------------------------------
29
+ // Placeholder — not implemented
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * @throws Always throws — order placement is not implemented in v0.
33
+ *
34
+ * @deprecated Not implemented. See module-level documentation.
35
+ */
36
+ function placeOrder() {
37
+ throw new Error('placeOrder is not implemented. ' +
38
+ 'Final order placement is out of scope for v0 of the Oda shopping assistant. ' +
39
+ 'See the OpenClaw plugin manifest (openclaw.plugin.json) for supported tool capabilities.');
40
+ }
41
+ exports.placeOrder = placeOrder;
42
+ //# sourceMappingURL=highRiskTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highRiskTools.js","sourceRoot":"","sources":["../../src/tools/highRiskTools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;;AAEH,8EAA8E;AAC9E,gCAAgC;AAChC,8EAA8E;AAE9E;;;;GAIG;AACH,SAAgB,UAAU;IACxB,MAAM,IAAI,KAAK,CACb,iCAAiC;QAC/B,8EAA8E;QAC9E,0FAA0F,CAC7F,CAAC;AACJ,CAAC;AAND,gCAMC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Read-only tools for the Oda shopping assistant.
3
+ *
4
+ * These tools are ENABLED by default. They do not mutate any state and are
5
+ * safe to invoke without explicit user confirmation.
6
+ *
7
+ * Tools exposed:
8
+ * - searchProducts — search the Oda product catalogue
9
+ * - getCart — read the current shopping cart
10
+ * - getOrders — read paginated order history
11
+ * - getDeliverySlots — list available delivery time slots
12
+ * - getShoppingLists — list the user's saved shopping lists
13
+ *
14
+ * Higher-level helpers (buildShoppingList, analyseOrderHistory,
15
+ * findCheapestDeliverySlot) are implemented in plugin.ts and compose
16
+ * these primitives without performing any writes.
17
+ */
18
+ import type { OdaClient, OdaSearchResponse, OdaCart, OdaPage, OdaOrder, OdaDeliverySlot, OdaShoppingList } from '@oda-agent/core';
19
+ /** Parameters for the searchProducts tool. */
20
+ export interface SearchProductsParams {
21
+ query: string;
22
+ }
23
+ /** Parameters for the getOrders tool. */
24
+ export interface GetOrdersParams {
25
+ /** Page number, 1-based. Defaults to 1. */
26
+ page?: number;
27
+ }
28
+ /**
29
+ * Search the Oda catalogue for products matching `query`.
30
+ * Returns the raw search response including matched products and result count.
31
+ */
32
+ export declare function searchProducts(client: OdaClient, params: SearchProductsParams): Promise<OdaSearchResponse>;
33
+ /**
34
+ * Retrieve the authenticated user's current shopping cart.
35
+ */
36
+ export declare function getCart(client: OdaClient): Promise<OdaCart>;
37
+ /**
38
+ * Fetch a page of the authenticated user's past orders.
39
+ */
40
+ export declare function getOrders(client: OdaClient, params?: GetOrdersParams): Promise<OdaPage<OdaOrder>>;
41
+ /**
42
+ * List all delivery time slots, both available and unavailable.
43
+ */
44
+ export declare function getDeliverySlots(client: OdaClient): Promise<OdaDeliverySlot[]>;
45
+ /**
46
+ * List the authenticated user's saved shopping lists.
47
+ */
48
+ export declare function getShoppingLists(client: OdaClient): Promise<OdaShoppingList[]>;
49
+ //# sourceMappingURL=readOnlyTools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readOnlyTools.d.ts","sourceRoot":"","sources":["../../src/tools/readOnlyTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMlI,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAEjE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,SAAS,EACjB,MAAM,GAAE,eAAoB,GAC3B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAEpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAEpF"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /**
3
+ * Read-only tools for the Oda shopping assistant.
4
+ *
5
+ * These tools are ENABLED by default. They do not mutate any state and are
6
+ * safe to invoke without explicit user confirmation.
7
+ *
8
+ * Tools exposed:
9
+ * - searchProducts — search the Oda product catalogue
10
+ * - getCart — read the current shopping cart
11
+ * - getOrders — read paginated order history
12
+ * - getDeliverySlots — list available delivery time slots
13
+ * - getShoppingLists — list the user's saved shopping lists
14
+ *
15
+ * Higher-level helpers (buildShoppingList, analyseOrderHistory,
16
+ * findCheapestDeliverySlot) are implemented in plugin.ts and compose
17
+ * these primitives without performing any writes.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.getShoppingLists = exports.getDeliverySlots = exports.getOrders = exports.getCart = exports.searchProducts = void 0;
21
+ // ---------------------------------------------------------------------------
22
+ // Tool implementations
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * Search the Oda catalogue for products matching `query`.
26
+ * Returns the raw search response including matched products and result count.
27
+ */
28
+ async function searchProducts(client, params) {
29
+ return client.searchProducts(params.query);
30
+ }
31
+ exports.searchProducts = searchProducts;
32
+ /**
33
+ * Retrieve the authenticated user's current shopping cart.
34
+ */
35
+ async function getCart(client) {
36
+ return client.getCart();
37
+ }
38
+ exports.getCart = getCart;
39
+ /**
40
+ * Fetch a page of the authenticated user's past orders.
41
+ */
42
+ async function getOrders(client, params = {}) {
43
+ return client.getOrders(params.page ?? 1);
44
+ }
45
+ exports.getOrders = getOrders;
46
+ /**
47
+ * List all delivery time slots, both available and unavailable.
48
+ */
49
+ async function getDeliverySlots(client) {
50
+ return client.getDeliverySlots();
51
+ }
52
+ exports.getDeliverySlots = getDeliverySlots;
53
+ /**
54
+ * List the authenticated user's saved shopping lists.
55
+ */
56
+ async function getShoppingLists(client) {
57
+ return client.getShoppingLists();
58
+ }
59
+ exports.getShoppingLists = getShoppingLists;
60
+ //# sourceMappingURL=readOnlyTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readOnlyTools.js","sourceRoot":"","sources":["../../src/tools/readOnlyTools.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;AAmBH,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E;;;GAGG;AACI,KAAK,UAAU,cAAc,CAClC,MAAiB,EACjB,MAA4B;IAE5B,OAAO,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7C,CAAC;AALD,wCAKC;AAED;;GAEG;AACI,KAAK,UAAU,OAAO,CAAC,MAAiB;IAC7C,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AAFD,0BAEC;AAED;;GAEG;AACI,KAAK,UAAU,SAAS,CAC7B,MAAiB,EACjB,SAA0B,EAAE;IAE5B,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;AAC5C,CAAC;AALD,8BAKC;AAED;;GAEG;AACI,KAAK,UAAU,gBAAgB,CAAC,MAAiB;IACtD,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC;AACnC,CAAC;AAFD,4CAEC;AAED;;GAEG;AACI,KAAK,UAAU,gBAAgB,CAAC,MAAiB;IACtD,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC;AACnC,CAAC;AAFD,4CAEC"}
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "oda-shopping-assistant",
3
+ "version": "0.1.0",
4
+ "description": "Oda grocery shopping assistant — safe cart planning, order history analysis, and delivery slot discovery.",
5
+ "author": "oda-agent-kit",
6
+ "license": "MIT",
7
+ "toolGroups": [
8
+ {
9
+ "name": "read-only",
10
+ "description": "Safe, read-only tools for browsing products, cart, orders, and delivery slots.",
11
+ "enabled": true,
12
+ "tools": [
13
+ {
14
+ "name": "searchProducts",
15
+ "description": "Search for products in the Oda catalogue by keyword."
16
+ },
17
+ {
18
+ "name": "getCart",
19
+ "description": "Retrieve the current shopping cart."
20
+ },
21
+ {
22
+ "name": "getOrders",
23
+ "description": "Fetch paginated order history."
24
+ },
25
+ {
26
+ "name": "getDeliverySlots",
27
+ "description": "List available delivery time slots."
28
+ },
29
+ {
30
+ "name": "getShoppingLists",
31
+ "description": "List the user's saved shopping lists."
32
+ },
33
+ {
34
+ "name": "analyseOrderHistory",
35
+ "description": "Analyse past orders and return a summary of frequently ordered products."
36
+ },
37
+ {
38
+ "name": "buildShoppingList",
39
+ "description": "Resolve plain-text queries into a structured shopping list without mutating the cart."
40
+ },
41
+ {
42
+ "name": "findCheapestDeliverySlot",
43
+ "description": "Return the cheapest available delivery slot without booking it."
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ "name": "cart-mutation",
49
+ "description": "Optional tools that modify the cart. Must be explicitly enabled by the user.",
50
+ "enabled": false,
51
+ "tools": [
52
+ {
53
+ "name": "prepareCart",
54
+ "description": "Add all items from a shopping list to the cart. Requires explicit user confirmation before use."
55
+ },
56
+ {
57
+ "name": "addToCart",
58
+ "description": "Add a single product to the cart. Requires explicit user confirmation before use."
59
+ },
60
+ {
61
+ "name": "removeFromCart",
62
+ "description": "Remove an item from the cart by cart-item ID from getCart (`cart.items[].id`). Requires explicit user confirmation before use."
63
+ },
64
+ {
65
+ "name": "clearCart",
66
+ "description": "Remove all items from the cart. Requires explicit user confirmation before use."
67
+ }
68
+ ]
69
+ },
70
+ {
71
+ "name": "high-risk",
72
+ "description": "High-risk tools for order placement and payment. OUT OF SCOPE for v0 — not implemented.",
73
+ "enabled": false,
74
+ "tools": [
75
+ {
76
+ "name": "placeOrder",
77
+ "description": "NOT IMPLEMENTED. Final order placement is out of scope for v0. See highRiskTools.ts."
78
+ }
79
+ ]
80
+ }
81
+ ],
82
+ "skills": [
83
+ {
84
+ "name": "oda-shopping-assistant",
85
+ "path": "skills/oda-shopping-assistant/SKILL.md"
86
+ }
87
+ ]
88
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@oda-agent/openclaw-plugin",
3
+ "version": "0.1.0",
4
+ "description": "OpenClaw plugin for safe grocery planning and Oda automation",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "openclaw.plugin.json",
10
+ "skills"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc --project tsconfig.json",
14
+ "clean": "rm -rf dist *.tsbuildinfo",
15
+ "lint": "eslint src --ext .ts",
16
+ "typecheck": "tsc --project tsconfig.json --noEmit",
17
+ "test": "jest"
18
+ },
19
+ "dependencies": {
20
+ "@oda-agent/core": "*"
21
+ },
22
+ "devDependencies": {
23
+ "@types/jest": "^29.5.0",
24
+ "jest": "^29.7.0",
25
+ "ts-jest": "^29.2.0"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/dinorastoder/oda-agent-kit.git"
30
+ },
31
+ "license": "MIT"
32
+ }
@@ -0,0 +1,96 @@
1
+ # Oda Shopping Assistant — Skill
2
+
3
+ ## Purpose
4
+
5
+ The Oda Shopping Assistant helps users plan, review, and (optionally) prepare grocery orders from the Norwegian online supermarket [Oda](https://oda.com). It follows a **safe-by-default** design: it reads and proposes, then waits for explicit user approval before making any changes.
6
+
7
+ ---
8
+
9
+ ## Grocery workflow
10
+
11
+ The assistant always follows this workflow:
12
+
13
+ 1. **Read** — Fetch the current cart, order history, saved lists, and available delivery slots.
14
+ 2. **Propose** — Build a suggested grocery plan based on past purchases, explicit requests, or both.
15
+ 3. **Explain** — For each suggested item, briefly explain *why* it is included (staple product, user request, substitute, etc.).
16
+ 4. **Confirm before cart changes** — Show a full summary of proposed cart changes and ask the user for approval.
17
+ 5. **Confirm before delivery-slot changes** — Ask for a separate, stronger confirmation before reserving or modifying a delivery slot.
18
+ 6. **Never place an order automatically** — Final order placement is not implemented in v0. The assistant must stop after cart preparation.
19
+
20
+ ---
21
+
22
+ ## Tool groups
23
+
24
+ ### Read-only tools (enabled by default)
25
+
26
+ These tools are safe to invoke without user confirmation. They observe but do not mutate.
27
+
28
+ | Tool | Description |
29
+ |------|-------------|
30
+ | `searchProducts` | Search the Oda catalogue by keyword |
31
+ | `getCart` | Read the current shopping cart |
32
+ | `getOrders` | Fetch paginated order history |
33
+ | `getDeliverySlots` | List available delivery time slots |
34
+ | `getShoppingLists` | List the user's saved shopping lists |
35
+ | `buildShoppingList` | Resolve plain-text queries into a structured shopping list |
36
+ | `analyseOrderHistory` | Summarise past orders and frequently bought products |
37
+ | `findCheapestDeliverySlot` | Find the cheapest available delivery slot (read-only) |
38
+
39
+ ### Cart-mutation tools (disabled by default)
40
+
41
+ These tools modify the shopping cart. They must be **explicitly enabled** by the user and require **explicit confirmation** before each invocation.
42
+
43
+ | Tool | Description |
44
+ |------|-------------|
45
+ | `prepareCart` | Bulk-add all items from a shopping list to the cart |
46
+ | `addToCart` | Add a single product to the cart |
47
+ | `removeFromCart` | Remove a cart item by cart-item ID (`cart.items[].id`) |
48
+ | `clearCart` | Remove all items from the cart |
49
+
50
+ ### High-risk tools (not implemented in v0)
51
+
52
+ Order placement and payment are **out of scope** for v0. The `placeOrder` tool is documented but not implemented. See `src/tools/highRiskTools.ts` for rationale and future-work notes.
53
+
54
+ ---
55
+
56
+ ## Safety model
57
+
58
+ - **Read first, write second** — never modify cart or delivery state without first showing the user what will change.
59
+ - **One confirmation per mutation class** — a single approval covers one named set of changes. New changes require a new confirmation.
60
+ - **No hidden writes** — the assistant must never add to or clear the cart as a side-effect of a read operation.
61
+ - **No payment logic** — the assistant cannot and must not handle payment information or finalise orders.
62
+ - **Secrets stay out of logs** — session tokens, CSRF tokens, and credentials are never logged or included in tool responses.
63
+
64
+ ---
65
+
66
+ ## Example conversation
67
+
68
+ ```
69
+ User: Can you suggest a weekly shop based on what I usually buy?
70
+
71
+ Agent: Sure! Here's a proposed list based on your last 5 orders:
72
+
73
+ 1. Oat Milk 1L × 2 — ordered 4 times in the last 3 months
74
+ 2. Sourdough Bread × 1 — ordered every week
75
+ 3. Greek Yoghurt 500g × 2 — ordered 3 times recently
76
+
77
+ Shall I add these to your cart? (yes / no / edit)
78
+
79
+ User: Yes, add them.
80
+
81
+ Agent: Adding 3 items to your cart…
82
+ ✓ Oat Milk 1L × 2
83
+ ✓ Sourdough Bread × 1
84
+ ✓ Greek Yoghurt 500g × 2
85
+
86
+ Done! Your cart now has 3 items. Would you like to browse
87
+ delivery slots?
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Limitations (v0)
93
+
94
+ - No final order placement — the workflow stops at cart preparation.
95
+ - No payment information is handled.
96
+ - Cart-mutation tools must be enabled by the operator before the assistant can modify the cart.