@tenderlead/cli 0.4.1 → 0.4.2
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/README.md +41 -0
- package/bin/tenderlead.js +26 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,12 +22,43 @@ Sign in with Google or an emailed sign-in link, then create a scoped token under
|
|
|
22
22
|
```bash
|
|
23
23
|
export TENDERLEAD_API_TOKEN="paste-token-here"
|
|
24
24
|
tenderlead whoami
|
|
25
|
+
tenderlead account status
|
|
25
26
|
tenderlead brief
|
|
26
27
|
```
|
|
27
28
|
|
|
28
29
|
`whoami` confirms which account and token the CLI is using (masked email, plan,
|
|
29
30
|
token label, scopes and expiry). It works with any valid token.
|
|
30
31
|
|
|
32
|
+
`account status` uses a `profile:read` token to report profile readiness,
|
|
33
|
+
personalised preview state and the number of opportunities in a released
|
|
34
|
+
preview. If setup is incomplete, it gives the next browser step. Preview
|
|
35
|
+
requests, trial start, token management and billing remain browser actions.
|
|
36
|
+
Existing profile fields can still be edited with `profile apply`.
|
|
37
|
+
|
|
38
|
+
The `account status` command is included in CLI 0.4.2 and uses the deployed
|
|
39
|
+
read-only route:
|
|
40
|
+
|
|
41
|
+
```http
|
|
42
|
+
GET /v1/account/status
|
|
43
|
+
Authorization: Bearer TENDERLEAD_API_TOKEN
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
It requires `profile:read` and returns a compact account-scoped response:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"account": { "active": false, "plan_tier": null, "plan_status": null, "trial_ends_at": null },
|
|
51
|
+
"profile": { "ready": true },
|
|
52
|
+
"preview": { "status": "sent", "requested_at": "2026-09-20T09:00:00.000Z", "briefing_sent_at": "2026-09-20T09:05:00.000Z" },
|
|
53
|
+
"released_opportunity_count": 3,
|
|
54
|
+
"next_action": { "action": "start_trial", "url": "https://tenderlead.co.uk/personalised-preview", "label": "Open your preview to start a trial or choose a plan" }
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The route does not return profile fields, email addresses or tender records.
|
|
59
|
+
Preview requests, trial activation and account-access changes use the returned
|
|
60
|
+
browser URL rather than adding CLI write access.
|
|
61
|
+
|
|
31
62
|
Use JSON output for scripts and agents:
|
|
32
63
|
|
|
33
64
|
```bash
|
|
@@ -149,6 +180,16 @@ Revoke exposed tokens in Settings.
|
|
|
149
180
|
Sign-in, token creation and revocation, Stripe checkout and billing, and
|
|
150
181
|
permanent account deletion remain browser tasks.
|
|
151
182
|
|
|
183
|
+
## OpenAI and Claude
|
|
184
|
+
|
|
185
|
+
TenderLead's published OpenAI integration connects through OAuth and provides
|
|
186
|
+
three read-only tools for the current brief, matched-tender search and saved
|
|
187
|
+
tender decisions. If the connected account has no active trial or paid plan,
|
|
188
|
+
the tool response links to the browser setup journey. Complete the company
|
|
189
|
+
profile there, request the free personalised preview or start a trial, then
|
|
190
|
+
retry the tool. The integration cannot change a profile, start a trial or alter
|
|
191
|
+
billing. Claude access remains a private beta.
|
|
192
|
+
|
|
152
193
|
Provider acceptance and API responses do not prove email inbox delivery.
|
|
153
194
|
|
|
154
195
|
## Requirements
|
package/bin/tenderlead.js
CHANGED
|
@@ -18,6 +18,7 @@ function usage() {
|
|
|
18
18
|
'Usage:',
|
|
19
19
|
' tenderlead login',
|
|
20
20
|
' tenderlead whoami [--json]',
|
|
21
|
+
' tenderlead account status [--json]',
|
|
21
22
|
' tenderlead brief [--json]',
|
|
22
23
|
' tenderlead tenders search [--query <text>] [--recommendation bid|skip] [--all] [--limit <1-50>] [--json]',
|
|
23
24
|
' tenderlead tender score <contract-id> [--json]',
|
|
@@ -63,6 +64,10 @@ function parseArgs(argv) {
|
|
|
63
64
|
const command = argv[2];
|
|
64
65
|
if (command === 'login') return { command: 'login' };
|
|
65
66
|
if (command === 'whoami') return parseJsonOnlyArgs(argv, 3, { command: 'whoami', json: false });
|
|
67
|
+
if (command === 'account') {
|
|
68
|
+
if (argv[3] !== 'status') throw new Error('Use account status.');
|
|
69
|
+
return parseJsonOnlyArgs(argv, 4, { command: 'account', action: 'status', json: false });
|
|
70
|
+
}
|
|
66
71
|
if (command === 'brief') {
|
|
67
72
|
const options = { command: 'brief', json: false };
|
|
68
73
|
for (let index = 3; index < argv.length; index += 1) {
|
|
@@ -364,6 +369,24 @@ function formatWhoami(payload) {
|
|
|
364
369
|
return rows.map(([label, value]) => `${label.padEnd(width)} ${value}`).join('\n');
|
|
365
370
|
}
|
|
366
371
|
|
|
372
|
+
function formatAccountStatus(payload) {
|
|
373
|
+
const account = payload.account || {};
|
|
374
|
+
const profile = payload.profile || {};
|
|
375
|
+
const preview = payload.preview || null;
|
|
376
|
+
const nextAction = payload.next_action || {};
|
|
377
|
+
return [
|
|
378
|
+
'# TenderLead account status',
|
|
379
|
+
'',
|
|
380
|
+
`Access: ${account.active ? 'active' : 'inactive'}`,
|
|
381
|
+
`Plan: ${line(account.plan_tier, 'not set')} (${line(account.plan_status, 'not active')})`,
|
|
382
|
+
`Profile: ${profile.ready ? 'ready' : 'incomplete'}`,
|
|
383
|
+
`Preview: ${preview ? line(preview.status, 'unknown') : 'not requested'}`,
|
|
384
|
+
`Released opportunities: ${Number(payload.released_opportunity_count) || 0}`,
|
|
385
|
+
'',
|
|
386
|
+
`Next: ${line(nextAction.label, 'Open TenderLead in your browser')}${nextAction.url ? `: ${nextAction.url}` : ''}`,
|
|
387
|
+
].join('\n');
|
|
388
|
+
}
|
|
389
|
+
|
|
367
390
|
function formatBrief(payload) {
|
|
368
391
|
const rows = Array.isArray(payload.opportunities) ? payload.opportunities : [];
|
|
369
392
|
const lines = ['# TenderLead daily brief', '', `Generated: ${line(payload.generated_at, 'Not recorded')}`, `Plan: ${line(payload.tier, 'Not recorded')}`, '', '## Opportunities', ''];
|
|
@@ -425,6 +448,7 @@ async function apiRequest(path, options = {}, fetchImpl = fetch) {
|
|
|
425
448
|
}
|
|
426
449
|
|
|
427
450
|
async function fetchWhoami(fetchImpl = fetch) { return apiRequest('/api/cli/whoami', {}, fetchImpl); }
|
|
451
|
+
async function fetchAccountStatus(fetchImpl = fetch) { return apiRequest('/v1/account/status', {}, fetchImpl); }
|
|
428
452
|
|
|
429
453
|
async function fetchBrief(_options, fetchImpl = fetch) {
|
|
430
454
|
return apiRequest('/v1/briefs/daily', {}, fetchImpl);
|
|
@@ -710,6 +734,7 @@ async function main() {
|
|
|
710
734
|
return;
|
|
711
735
|
}
|
|
712
736
|
if (options.command === 'whoami') return printPayload(await fetchWhoami(), options.json, formatWhoami);
|
|
737
|
+
if (options.command === 'account') return printPayload(await fetchAccountStatus(), options.json, formatAccountStatus);
|
|
713
738
|
if (options.command === 'brief') {
|
|
714
739
|
const brief = await fetchBrief(options);
|
|
715
740
|
console.log(options.json ? JSON.stringify(brief, null, 2) : formatBrief(brief));
|
|
@@ -843,7 +868,7 @@ if (require.main === module) {
|
|
|
843
868
|
}
|
|
844
869
|
|
|
845
870
|
module.exports = {
|
|
846
|
-
parseArgs, openLogin, fetchWhoami, formatWhoami, formatBrief, formatTenders, formatScore, fetchBrief, searchTenders, scoreTender, fetchProfile, updateProfile,
|
|
871
|
+
parseArgs, openLogin, fetchWhoami, fetchAccountStatus, formatWhoami, formatAccountStatus, formatBrief, formatTenders, formatScore, fetchBrief, searchTenders, scoreTender, fetchProfile, updateProfile,
|
|
847
872
|
validateProfile, readProfileFile, profileTemplate, profileDiff, formatProfile,
|
|
848
873
|
formatProfileDiff, confirmApply, confirmWord, readJsonFile, contentTypeForFile, appendFiles,
|
|
849
874
|
fetchPipeline, addPipelineItem, updatePipelineItem, removePipelineItem, fetchInsights, sendTenderFeedback, sendProductFeedback,
|
package/package.json
CHANGED