From 7456c117e2664275c00e2e8c907aea46abe7c05b Mon Sep 17 00:00:00 2001 From: Dave Oster Date: Tue, 13 Oct 2026 09:17:39 -0500 Subject: [PATCH] Sync feature-2 prospect statuses and shared contracts --- npm-alias/package.json | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- src/commands/prospects.ts | 19 ++++++++++++++++++- src/index.ts | 4 ++-- src/version.ts | 2 +- tests/commands/prospects.test.ts | 22 +++++++++++++++++++++- 7 files changed, 47 insertions(+), 10 deletions(-) diff --git a/npm-alias/package.json b/npm-alias/package.json index bb59082..9acfaa7 100644 --- a/npm-alias/package.json +++ b/npm-alias/package.json @@ -1,6 +1,6 @@ { "name": "dealmachine", - "version": "0.4.1-rc.1", + "version": "0.4.1-rc.2", "description": "Short install alias for the DealMachine property intelligence CLI", "author": "DealMachine", "license": "MIT", @@ -23,7 +23,7 @@ "LICENSE" ], "dependencies": { - "@dealmachine/cli": "0.4.1-rc.1" + "@dealmachine/cli": "0.4.1-rc.2" }, "engines": { "node": ">=18" diff --git a/package-lock.json b/package-lock.json index 651103f..c4223ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dealmachine/cli", - "version": "0.4.1-rc.1", + "version": "0.4.1-rc.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dealmachine/cli", - "version": "0.4.1-rc.1", + "version": "0.4.1-rc.2", "license": "MIT", "dependencies": { "chalk": "^5.3.0", diff --git a/package.json b/package.json index e53a8e0..f230193 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dealmachine/cli", - "version": "0.4.1-rc.1", + "version": "0.4.1-rc.2", "description": "DealMachine CLI for property intelligence, people lookup, and enrichment through the public API", "author": "DealMachine", "license": "MIT", diff --git a/src/commands/prospects.ts b/src/commands/prospects.ts index 34e9736..d94c4a1 100644 --- a/src/commands/prospects.ts +++ b/src/commands/prospects.ts @@ -26,6 +26,8 @@ type Prospect = { record_id: string; lifecycle: string; favorite: boolean; + /** Read only: hot, warm, cold, follow_up, do_not_contact, or null. */ + status?: string | null; source: string; record: { address?: string | null; @@ -56,16 +58,29 @@ function recordLabel(prospect: Prospect): string { return place ? `${main} (${place})` : String(main); } +const STATUS_LABELS: Record = { + hot: 'Hot', + warm: 'Warm', + cold: 'Cold', + follow_up: 'Follow up', + do_not_contact: 'Do Not Contact', +}; + +function statusLabel(prospect: Prospect): string { + return prospect.status ? (STATUS_LABELS[prospect.status] ?? prospect.status) : 'None'; +} + function printProspectRows(prospects: Prospect[]) { const rows = prospects.map((p) => ({ id: p.id, record: truncate(recordLabel(p), 44), lifecycle: p.lifecycle, fav: p.favorite ? '★' : '', + status: statusLabel(p), tags: truncate(p.tags.map((tag) => tag.name).join(', ') || '—', 24), added: formatDate(p.created_at), })); - printTable(rows, ['id', 'record', 'lifecycle', 'fav', 'tags', 'added']); + printTable(rows, ['id', 'record', 'lifecycle', 'fav', 'status', 'tags', 'added']); } function printPagination(p: Pagination) { @@ -138,6 +153,7 @@ export async function prospectsGet(id: string, options: { json?: boolean }): Pro Type: p.record_type, Lifecycle: p.lifecycle, Favorite: p.favorite ? 'Yes' : 'No', + Status: statusLabel(p), Source: p.source, Tags: p.tags.map((tag) => `${tag.name} (${tag.id})`).join(', ') || '—', Notes: String(p.note_count ?? 0), @@ -173,6 +189,7 @@ export async function prospectsGetByRecord(options: { Type: p.record_type, Lifecycle: p.lifecycle, Favorite: p.favorite ? 'Yes' : 'No', + Status: statusLabel(p), Source: p.source, Tags: p.tags.map((tag) => `${tag.name} (${tag.id})`).join(', ') || '—', Added: formatDate(p.created_at), diff --git a/src/index.ts b/src/index.ts index 390e7b5..52592c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1642,7 +1642,7 @@ prospectsCmd .option('--source ', 'Filter by source, e.g. driving, import, api, cli, or mcp') .option('--favorites', 'Only starred prospects') .option('--list ', 'Only members of this list') - .option('--tag ', 'Only prospects with this tag, e.g. tag_5') + .option('--tag ', 'Only prospects with this tag, e.g. tag_31') .option('--search ', 'Address words for properties; name or city for people') .option('--sort ', 'newest (default) or oldest') .option('-p, --page ', 'Page number') @@ -1654,7 +1654,7 @@ prospectsCmd Examples: dm prospects list dm prospects list --source driving - dm prospects list --lifecycle opportunity --tag tag_1 + dm prospects list --lifecycle opportunity --tag tag_31 dm prospects list --record-type person --search "austin" --json` ) .action(async (options) => { diff --git a/src/version.ts b/src/version.ts index 7e3739b..d4bb406 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,2 +1,2 @@ -export const CLI_VERSION = '0.4.1-rc.1'; +export const CLI_VERSION = '0.4.1-rc.2'; export const CLI_USER_AGENT = `dm-cli/${CLI_VERSION}`; diff --git a/tests/commands/prospects.test.ts b/tests/commands/prospects.test.ts index b6976fe..6e61b47 100644 --- a/tests/commands/prospects.test.ts +++ b/tests/commands/prospects.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { prospectsArchive, prospectsReactivate } from '../../src/commands/prospects.js'; +import { prospectsArchive, prospectsReactivate, prospectsGet } from '../../src/commands/prospects.js'; vi.mock('../../src/lib/config.js', () => ({ readConfig: () => ({ apiKey: 'fixture-only', apiEnvironment: 'staging' }), @@ -134,3 +134,23 @@ describe('dm prospects reactivate', () => { expect(log.mock.calls.flat().join('\n')).toContain('Prospects Restored'); }); }); + +// Public output remains usable with both the additive field and older API responses. +describe('dm prospects status display', () => { + it.each([ + ['do_not_contact', 'Do Not Contact'], + ['follow_up', 'Follow up'], + [null, 'None'], + [undefined, 'None'], + ])('shows status %s on the prospect detail', async (status, label) => { + fetchMock.mockResolvedValue(jsonResponse(200, { data: { + id: 'prospect_8812', record_type: 'property', record_id: 'prop_1', + lifecycle: 'active', favorite: false, status, source: 'api', + record: { address: '123 Main St' }, tags: [], created_at: '2026-10-13T00:00:00Z', + } })); + await prospectsGet('prospect_8812', {}); + const printed = log.mock.calls.flat().join('\n'); + expect(printed).toContain('Status'); + expect(printed).toContain(label); + }); +});