From 557280eb0ef9de34ce87ab26aef2223a26e90829 Mon Sep 17 00:00:00 2001 From: "Carson (Claude Assistant)" Date: Sun, 8 Mar 2026 22:38:30 +0100 Subject: [PATCH] Convert to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Renamed bring → bring.ts - Added TypeScript interfaces for type safety - Added tsconfig.json for TypeScript configuration - Updated package.json with TypeScript dependencies - Updated SKILL.md with TypeScript usage instructions - Added dist/ to .gitignore Co-Authored-By: Claude Sonnet 4.5 --- .gitignore | 2 ++ SKILL.md | 37 +++++++++++++++++++--------- bring => bring.ts | 62 ++++++++++++++++++++++++++++++----------------- package.json | 12 ++++++++- tsconfig.json | 19 +++++++++++++++ 5 files changed, 98 insertions(+), 34 deletions(-) rename bring => bring.ts (65%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index b96e262..730d31e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules/ package-lock.json *.log .env +dist/ +*.tsbuildinfo diff --git a/SKILL.md b/SKILL.md index 8e6b67d..7d0f6a0 100644 --- a/SKILL.md +++ b/SKILL.md @@ -2,11 +2,21 @@ Manage your Bring! Shopping List via CLI using the unofficial Bring! API. +TypeScript implementation with full type safety. + ## Installation ```bash npm install -chmod +x bring +chmod +x bring.ts +``` + +Or to build and run as JavaScript: + +```bash +npm install +npm run build +node dist/bring.js ``` ## Configuration @@ -63,28 +73,33 @@ console.log(lists.lists); // Shows all lists with their UUIDs ## Commands ```bash -bring add [specification] # Add item to shopping list -bring list # Show current items -bring remove # Remove item (mark as purchased) -bring recent # Show recently purchased items +./bring.ts add [specification] # Add item to shopping list +./bring.ts list # Show current items +./bring.ts remove # Remove item (mark as purchased) +./bring.ts recent # Show recently purchased items +``` + +Or using ts-node directly: +```bash +ts-node bring.ts add ``` ## Examples ```bash # Add items -bring add Apples -bring add Milk "1 Liter" -bring add "Coffee Beans" "Fair Trade" +./bring.ts add Apples +./bring.ts add Milk "1 Liter" +./bring.ts add "Coffee Beans" "Fair Trade" # Show list -bring list +./bring.ts list # Remove item (mark as bought) -bring remove Apples +./bring.ts remove Apples # Show recently purchased items -bring recent +./bring.ts recent ``` ## Integration with AI Agents diff --git a/bring b/bring.ts similarity index 65% rename from bring rename to bring.ts index fbd7db1..832df76 100755 --- a/bring +++ b/bring.ts @@ -1,14 +1,31 @@ -#!/usr/bin/env node +#!/usr/bin/env ts-node -const bringApi = require('bring-shopping'); +import BringApi from 'bring-shopping'; + +interface Credentials { + mail: string; + password: string; +} + +interface BringItem { + name: string; + specification: string; +} + +interface BringItems { + uuid: string; + status: string; + purchase: BringItem[]; + recently: BringItem[]; +} // Load credentials from environment variables -const CREDENTIALS = { - mail: process.env.BRING_EMAIL, - password: process.env.BRING_PASSWORD +const CREDENTIALS: Credentials = { + mail: process.env.BRING_EMAIL || '', + password: process.env.BRING_PASSWORD || '' }; -const LIST_UUID = process.env.BRING_LIST_UUID; +const LIST_UUID: string = process.env.BRING_LIST_UUID || ''; // Validate required environment variables if (!CREDENTIALS.mail || !CREDENTIALS.password || !LIST_UUID) { @@ -18,16 +35,16 @@ if (!CREDENTIALS.mail || !CREDENTIALS.password || !LIST_UUID) { process.exit(1); } -async function main() { - const args = process.argv.slice(2); - const command = args[0]; +async function main(): Promise { + const args: string[] = process.argv.slice(2); + const command: string | undefined = args[0]; if (!command) { console.error('Usage: bring [args...]'); process.exit(1); } - const bring = new bringApi(CREDENTIALS); + const bring = new BringApi(CREDENTIALS); try { await bring.login(); @@ -51,7 +68,8 @@ async function main() { process.exit(1); } } catch (error) { - console.error('Error:', error.message); + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error('Error:', errorMessage); process.exit(1); } } @@ -59,9 +77,9 @@ async function main() { /** * Add an item to the shopping list */ -async function addItem(bring, args) { - const itemName = args[0]; - const specification = args.slice(1).join(' ') || ''; +async function addItem(bring: any, args: string[]): Promise { + const itemName: string | undefined = args[0]; + const specification: string = args.slice(1).join(' ') || ''; if (!itemName) { console.error('Usage: bring add [specification]'); @@ -80,8 +98,8 @@ async function addItem(bring, args) { /** * List all items currently on the shopping list */ -async function listItems(bring) { - const items = await bring.getItems(LIST_UUID); +async function listItems(bring: any): Promise { + const items: BringItems = await bring.getItems(LIST_UUID); if (items.purchase.length === 0) { console.log('Shopping list is empty'); @@ -90,7 +108,7 @@ async function listItems(bring) { console.log('Shopping list:'); console.log(''); - items.purchase.forEach((item, index) => { + items.purchase.forEach((item: BringItem, index: number) => { if (item.specification) { console.log(`${index + 1}. ${item.name} (${item.specification})`); } else { @@ -102,8 +120,8 @@ async function listItems(bring) { /** * Remove an item from the shopping list (mark as purchased) */ -async function removeItem(bring, args) { - const itemName = args.join(' '); +async function removeItem(bring: any, args: string[]): Promise { + const itemName: string = args.join(' '); if (!itemName) { console.error('Usage: bring remove '); @@ -117,8 +135,8 @@ async function removeItem(bring, args) { /** * Show recently purchased items */ -async function recentItems(bring) { - const items = await bring.getItems(LIST_UUID); +async function recentItems(bring: any): Promise { + const items: BringItems = await bring.getItems(LIST_UUID); if (items.recently.length === 0) { console.log('No recently purchased items'); @@ -127,7 +145,7 @@ async function recentItems(bring) { console.log('Recently purchased:'); console.log(''); - items.recently.slice(0, 10).forEach((item, index) => { + items.recently.slice(0, 10).forEach((item: BringItem, index: number) => { if (item.specification) { console.log(`${index + 1}. ${item.name} (${item.specification})`); } else { diff --git a/package.json b/package.json index 3ca8c39..9325999 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,18 @@ { "name": "bring-shopping-skill", "version": "1.0.0", - "description": "Bring! Shopping List Skill for Carson", + "description": "Bring! Shopping List Skill - TypeScript CLI", + "type": "module", + "scripts": { + "build": "tsc", + "start": "ts-node bring.ts" + }, "dependencies": { "bring-shopping": "^2.0.1" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "ts-node": "^10.9.0", + "typescript": "^5.0.0" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2d062a4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["*.ts"], + "exclude": ["node_modules", "dist"] +}