@secondcontext/btx-cli 0.0.3 → 0.0.6
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 +11 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +1 -1
- package/dist/api.js.map +1 -1
- package/dist/bin.js +351 -21
- package/dist/bin.js.map +1 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +31 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +103 -21
- package/dist/login.js.map +1 -1
- package/dist/messages.d.ts +127 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +112 -0
- package/dist/messages.js.map +1 -0
- package/dist/runtime-cli.d.ts.map +1 -1
- package/dist/runtime-cli.js +391 -7
- package/dist/runtime-cli.js.map +1 -1
- package/package.json +1 -1
package/dist/messages.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { projectApiGet, projectApiPost } from './api.js';
|
|
2
|
+
function normalizeMatchValue(value) {
|
|
3
|
+
return value?.trim().toLowerCase() ?? '';
|
|
4
|
+
}
|
|
5
|
+
function formatMember(member) {
|
|
6
|
+
const name = member.name?.trim();
|
|
7
|
+
const email = member.email?.trim();
|
|
8
|
+
if (name && email)
|
|
9
|
+
return `${name} <${email}> [${member.userId}]`;
|
|
10
|
+
if (name)
|
|
11
|
+
return `${name} [${member.userId}]`;
|
|
12
|
+
if (email)
|
|
13
|
+
return `${email} [${member.userId}]`;
|
|
14
|
+
return member.userId;
|
|
15
|
+
}
|
|
16
|
+
function formatConversation(conversation) {
|
|
17
|
+
return `${conversation.name} [${conversation.id}]`;
|
|
18
|
+
}
|
|
19
|
+
function resolveUniqueMatch(query, items, selectors, render, itemLabel, listCommand) {
|
|
20
|
+
const normalizedQuery = normalizeMatchValue(query);
|
|
21
|
+
if (!normalizedQuery) {
|
|
22
|
+
throw new Error(`Provide a ${itemLabel} value.`);
|
|
23
|
+
}
|
|
24
|
+
const exactMatches = items.filter((item) => selectors.some((selector) => normalizeMatchValue(selector(item)) === normalizedQuery));
|
|
25
|
+
if (exactMatches.length === 1)
|
|
26
|
+
return exactMatches[0];
|
|
27
|
+
if (exactMatches.length > 1) {
|
|
28
|
+
throw new Error(`Multiple ${itemLabel}s match "${query}". Narrow the query or inspect ${listCommand}:\n${exactMatches
|
|
29
|
+
.map((item) => ` ${render(item)}`)
|
|
30
|
+
.join('\n')}`);
|
|
31
|
+
}
|
|
32
|
+
const partialMatches = items.filter((item) => selectors.some((selector) => normalizeMatchValue(selector(item)).includes(normalizedQuery)));
|
|
33
|
+
if (partialMatches.length === 1)
|
|
34
|
+
return partialMatches[0];
|
|
35
|
+
if (partialMatches.length > 1) {
|
|
36
|
+
throw new Error(`Multiple ${itemLabel}s match "${query}". Narrow the query or inspect ${listCommand}:\n${partialMatches
|
|
37
|
+
.map((item) => ` ${render(item)}`)
|
|
38
|
+
.join('\n')}`);
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`No ${itemLabel} matched "${query}". Run \`${listCommand}\` to inspect valid targets.`);
|
|
41
|
+
}
|
|
42
|
+
function formatScopeLabel(kind, label) {
|
|
43
|
+
switch (kind) {
|
|
44
|
+
case 'team':
|
|
45
|
+
return 'Team chat';
|
|
46
|
+
case 'dm':
|
|
47
|
+
return `Direct message with ${label}`;
|
|
48
|
+
case 'conversation':
|
|
49
|
+
return `Conversation: ${label}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export async function listProjectMembers(env) {
|
|
53
|
+
return projectApiGet(env, '/members');
|
|
54
|
+
}
|
|
55
|
+
export async function listChatConversations(env) {
|
|
56
|
+
return projectApiGet(env, '/chat/conversations');
|
|
57
|
+
}
|
|
58
|
+
export async function resolveMessageScope(env, flags) {
|
|
59
|
+
if (flags.peer && flags.conversation) {
|
|
60
|
+
throw new Error('Use either `--peer` or `--conversation`, not both.');
|
|
61
|
+
}
|
|
62
|
+
if (flags.peer) {
|
|
63
|
+
const members = await listProjectMembers(env);
|
|
64
|
+
const peer = resolveUniqueMatch(flags.peer, members, [
|
|
65
|
+
(member) => member.userId,
|
|
66
|
+
(member) => member.id,
|
|
67
|
+
(member) => member.email,
|
|
68
|
+
(member) => member.name,
|
|
69
|
+
], formatMember, 'member', 'btx messages members');
|
|
70
|
+
return {
|
|
71
|
+
kind: 'dm',
|
|
72
|
+
label: formatScopeLabel('dm', formatMember(peer)),
|
|
73
|
+
peer,
|
|
74
|
+
requestQuery: { peer: peer.userId },
|
|
75
|
+
sendPayload: { recipientId: peer.userId },
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (flags.conversation) {
|
|
79
|
+
const { conversations } = await listChatConversations(env);
|
|
80
|
+
const conversation = resolveUniqueMatch(flags.conversation, conversations, [(item) => item.id, (item) => item.name], formatConversation, 'conversation', 'btx messages conversations');
|
|
81
|
+
return {
|
|
82
|
+
kind: 'conversation',
|
|
83
|
+
label: formatScopeLabel('conversation', formatConversation(conversation)),
|
|
84
|
+
conversation,
|
|
85
|
+
requestQuery: { conversation: conversation.id },
|
|
86
|
+
sendPayload: { conversationId: conversation.id },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
kind: 'team',
|
|
91
|
+
label: formatScopeLabel('team', 'Team chat'),
|
|
92
|
+
requestQuery: {},
|
|
93
|
+
sendPayload: {},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export async function listChatMessages(env, scope, options) {
|
|
97
|
+
const params = new URLSearchParams(scope.requestQuery);
|
|
98
|
+
if (options.before)
|
|
99
|
+
params.set('before', options.before);
|
|
100
|
+
if (typeof options.limit === 'number')
|
|
101
|
+
params.set('limit', String(options.limit));
|
|
102
|
+
const suffix = params.toString();
|
|
103
|
+
return projectApiGet(env, `/chat${suffix ? `?${suffix}` : ''}`);
|
|
104
|
+
}
|
|
105
|
+
export async function sendChatMessage(env, scope, input) {
|
|
106
|
+
return projectApiPost(env, '/chat', {
|
|
107
|
+
body: input.body,
|
|
108
|
+
replyToId: input.replyToId ?? null,
|
|
109
|
+
...scope.sendPayload,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-cli.d.ts","sourceRoot":"","sources":["../src/runtime-cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime-cli.d.ts","sourceRoot":"","sources":["../src/runtime-cli.ts"],"names":[],"mappings":"AAiPA,MAAM,WAAW,aAAa;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AA48ED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,GAAE,aAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC,CA+Rf"}
|
package/dist/runtime-cli.js
CHANGED
|
@@ -138,6 +138,15 @@ function isJson(flags) {
|
|
|
138
138
|
function printJson(value) {
|
|
139
139
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
140
140
|
}
|
|
141
|
+
function readIntFlag(flags, key, defaultValue, min = 1, max = 200) {
|
|
142
|
+
const raw = flags[key];
|
|
143
|
+
if (!raw)
|
|
144
|
+
return defaultValue;
|
|
145
|
+
const parsed = Number.parseInt(raw, 10);
|
|
146
|
+
if (!Number.isFinite(parsed))
|
|
147
|
+
return defaultValue;
|
|
148
|
+
return Math.max(min, Math.min(max, parsed));
|
|
149
|
+
}
|
|
141
150
|
// ── Formatting ──────────────────────────────────────────────────────────────
|
|
142
151
|
function truncate(str, max) {
|
|
143
152
|
if (!str)
|
|
@@ -356,9 +365,198 @@ function formatMeetingTranscript(m) {
|
|
|
356
365
|
console.log(`[${time}] ${speaker}: ${seg.text}`);
|
|
357
366
|
}
|
|
358
367
|
}
|
|
368
|
+
function recordingTitle(recording) {
|
|
369
|
+
return (recording.meetingTitle?.trim() ||
|
|
370
|
+
recording.originalFilename?.trim() ||
|
|
371
|
+
'Untitled recording');
|
|
372
|
+
}
|
|
373
|
+
function recordingTimestamp(recording) {
|
|
374
|
+
return recording.meetingDate || recording.uploadedAt || recording.transcribedAt || recording.createdAt || null;
|
|
375
|
+
}
|
|
376
|
+
function formatRecordingDuration(durationMs) {
|
|
377
|
+
if (!durationMs || durationMs <= 0)
|
|
378
|
+
return '';
|
|
379
|
+
const totalSeconds = Math.max(0, Math.floor(durationMs / 1000));
|
|
380
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
381
|
+
const seconds = totalSeconds % 60;
|
|
382
|
+
const hours = Math.floor(minutes / 60);
|
|
383
|
+
if (hours > 0) {
|
|
384
|
+
return `${hours}:${String(minutes % 60).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
385
|
+
}
|
|
386
|
+
return `${minutes}:${String(seconds).padStart(2, '0')}`;
|
|
387
|
+
}
|
|
388
|
+
function formatRecordingTable(recordings) {
|
|
389
|
+
if (recordings.length === 0) {
|
|
390
|
+
console.log('No recordings found.');
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const idW = 10;
|
|
394
|
+
const dateW = 12;
|
|
395
|
+
const statusW = 12;
|
|
396
|
+
const sourceW = 12;
|
|
397
|
+
const durationW = 8;
|
|
398
|
+
console.log(`${padRight('ID', idW)} ${padRight('Date', dateW)} ${padRight('Status', statusW)} ${padRight('Source', sourceW)} ${padRight('Dur', durationW)} Title`);
|
|
399
|
+
console.log(`${'\u2500'.repeat(idW)} ${'\u2500'.repeat(dateW)} ${'\u2500'.repeat(statusW)} ${'\u2500'.repeat(sourceW)} ${'\u2500'.repeat(durationW)} ${'\u2500'.repeat(40)}`);
|
|
400
|
+
for (const recording of recordings) {
|
|
401
|
+
const date = recordingTimestamp(recording)
|
|
402
|
+
? new Date(recordingTimestamp(recording)).toISOString().slice(0, 10)
|
|
403
|
+
: '';
|
|
404
|
+
console.log(`${padRight(truncate(recording.id, idW), idW)} ${padRight(date, dateW)} ${padRight(truncate(recording.status || '', statusW), statusW)} ${padRight(truncate(recording.source || '', sourceW), sourceW)} ${padRight(formatRecordingDuration(recording.durationMs), durationW)} ${truncate(recordingTitle(recording), 52)}`);
|
|
405
|
+
}
|
|
406
|
+
console.log(`\n${recordings.length} recording${recordings.length !== 1 ? 's' : ''} found`);
|
|
407
|
+
}
|
|
408
|
+
function formatRecordingDetail(recording) {
|
|
409
|
+
console.log(`Recording: ${recordingTitle(recording)}`);
|
|
410
|
+
console.log(`ID: ${recording.id}`);
|
|
411
|
+
if (recording.meetingId)
|
|
412
|
+
console.log(`Meeting ID: ${recording.meetingId}`);
|
|
413
|
+
if (recordingTimestamp(recording)) {
|
|
414
|
+
console.log(`Date: ${new Date(recordingTimestamp(recording)).toISOString().slice(0, 10)}`);
|
|
415
|
+
}
|
|
416
|
+
if (recording.source)
|
|
417
|
+
console.log(`Source: ${recording.source}`);
|
|
418
|
+
if (recording.status)
|
|
419
|
+
console.log(`Status: ${recording.status}`);
|
|
420
|
+
if (recording.kind)
|
|
421
|
+
console.log(`Kind: ${recording.kind}`);
|
|
422
|
+
if (recording.captureMode)
|
|
423
|
+
console.log(`Capture: ${recording.captureMode}`);
|
|
424
|
+
if (recording.languageHint) {
|
|
425
|
+
const detected = recording.detectedLanguage ? ` (detected ${recording.detectedLanguage})` : '';
|
|
426
|
+
console.log(`Language: ${recording.languageHint}${detected}`);
|
|
427
|
+
}
|
|
428
|
+
if (recording.durationMs)
|
|
429
|
+
console.log(`Duration: ${formatRecordingDuration(recording.durationMs)}`);
|
|
430
|
+
if (recording.originalFilename)
|
|
431
|
+
console.log(`Filename: ${recording.originalFilename}`);
|
|
432
|
+
if (recording.mimeType)
|
|
433
|
+
console.log(`MIME: ${recording.mimeType}`);
|
|
434
|
+
if (recording.error)
|
|
435
|
+
console.log(`Error: ${recording.error}`);
|
|
436
|
+
if (recording.transcriptText?.trim()) {
|
|
437
|
+
console.log(`\nTranscript Preview:\n ${recording.transcriptText.trim().replace(/\n/g, '\n ')}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function recordingSpeakerLabel(source) {
|
|
441
|
+
const normalized = source?.trim();
|
|
442
|
+
if (!normalized)
|
|
443
|
+
return 'Speaker';
|
|
444
|
+
return normalized.replace(/[_-]+/g, ' ');
|
|
445
|
+
}
|
|
446
|
+
function formatRecordingTranscript(recording) {
|
|
447
|
+
const transcript = recording.transcript ?? [];
|
|
448
|
+
const transcriptText = recording.transcriptText?.trim() ?? '';
|
|
449
|
+
if (transcript.length === 0 && !transcriptText) {
|
|
450
|
+
console.log('No transcript available for this recording.');
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
console.log(`Transcript: ${recordingTitle(recording)}`);
|
|
454
|
+
if (recordingTimestamp(recording)) {
|
|
455
|
+
console.log(`Date: ${new Date(recordingTimestamp(recording)).toISOString().slice(0, 10)}`);
|
|
456
|
+
}
|
|
457
|
+
if (transcript.length > 0) {
|
|
458
|
+
console.log(`Segments: ${transcript.length}`);
|
|
459
|
+
console.log('');
|
|
460
|
+
for (const segment of transcript) {
|
|
461
|
+
const time = segment.start_time || '';
|
|
462
|
+
console.log(`[${time}] ${recordingSpeakerLabel(segment.speaker?.source)}: ${segment.text}`);
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
console.log('');
|
|
467
|
+
console.log(transcriptText);
|
|
468
|
+
}
|
|
469
|
+
function sessionPayload(s) {
|
|
470
|
+
return JSON.stringify({
|
|
471
|
+
sessionId: s.sessionId,
|
|
472
|
+
label: s.label,
|
|
473
|
+
sessionType: s.sessionType,
|
|
474
|
+
runtime: s.runtime || null,
|
|
475
|
+
status: s.status,
|
|
476
|
+
messageCount: s.messageCount ?? 0,
|
|
477
|
+
activityCount: s.activityCount ?? 0,
|
|
478
|
+
summary: s.summary ?? null,
|
|
479
|
+
lastActivityType: s.lastActivityType ?? null,
|
|
480
|
+
lastActivityContent: s.lastActivityContent ?? null,
|
|
481
|
+
createdAt: typeof s.createdAt === 'number'
|
|
482
|
+
? new Date(s.createdAt).toISOString()
|
|
483
|
+
: s.createdAt,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
function sessionPreview(session) {
|
|
487
|
+
return session.summary || session.lastActivityContent || '';
|
|
488
|
+
}
|
|
489
|
+
function formatSessionTable(sessions) {
|
|
490
|
+
if (sessions.length === 0) {
|
|
491
|
+
console.log('No sessions found.');
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
const idW = 12;
|
|
495
|
+
const dateW = 10;
|
|
496
|
+
const statusW = 8;
|
|
497
|
+
const typeW = 14;
|
|
498
|
+
const runtimeW = 12;
|
|
499
|
+
const labelW = 28;
|
|
500
|
+
console.log(`${padRight('ID', idW)} ${padRight('Date', dateW)} ${padRight('Status', statusW)} ${padRight('Type', typeW)} ${padRight('Runtime', runtimeW)} ${padRight('Label', labelW)} Preview`);
|
|
501
|
+
console.log(`${'\u2500'.repeat(idW)} ${'\u2500'.repeat(dateW)} ${'\u2500'.repeat(statusW)} ${'\u2500'.repeat(typeW)} ${'\u2500'.repeat(runtimeW)} ${'\u2500'.repeat(labelW)} ${'\u2500'.repeat(36)}`);
|
|
502
|
+
for (const session of sessions) {
|
|
503
|
+
const created = new Date(session.createdAt).toISOString().slice(0, 10);
|
|
504
|
+
console.log(`${padRight(truncate(session.sessionId, idW), idW)} ${padRight(created, dateW)} ${padRight(session.status, statusW)} ${padRight(truncate(session.sessionType, typeW), typeW)} ${padRight(truncate(session.runtime || '', runtimeW), runtimeW)} ${padRight(truncate(session.label, labelW), labelW)} ${truncate(sessionPreview(session), 44)}`);
|
|
505
|
+
}
|
|
506
|
+
console.log(`\n${sessions.length} session${sessions.length !== 1 ? 's' : ''} found`);
|
|
507
|
+
console.log('Use `btx sessions get <session-id>` for full details and recent checkpoints.');
|
|
508
|
+
for (const session of sessions) {
|
|
509
|
+
console.log(`BTX_SESSION_JSON: ${sessionPayload(session)}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function formatSessionDetail(session, activities) {
|
|
513
|
+
console.log(`Session: ${session.label}`);
|
|
514
|
+
console.log(`ID: ${session.sessionId}`);
|
|
515
|
+
console.log(`Status: ${session.status}`);
|
|
516
|
+
console.log(`Type: ${session.sessionType}`);
|
|
517
|
+
console.log(`Runtime: ${session.runtime || 'n/a'}`);
|
|
518
|
+
console.log(`Execution: ${session.executionMode}`);
|
|
519
|
+
console.log(`Started: ${new Date(session.createdAt).toISOString()}`);
|
|
520
|
+
if (session.updatedAt)
|
|
521
|
+
console.log(`Updated: ${new Date(session.updatedAt).toISOString()}`);
|
|
522
|
+
if (session.closedAt)
|
|
523
|
+
console.log(`Closed: ${session.closedAt}`);
|
|
524
|
+
if (session.userName || session.userEmail) {
|
|
525
|
+
console.log(`Owner: ${session.userName || session.userEmail}`);
|
|
526
|
+
}
|
|
527
|
+
console.log(`Messages: ${session.messageCount ?? 0}`);
|
|
528
|
+
console.log(`Activities: ${session.activityCount ?? 0}`);
|
|
529
|
+
if (session.totalCostUsd != null)
|
|
530
|
+
console.log(`Cost USD: ${session.totalCostUsd}`);
|
|
531
|
+
if (session.lastActivityType)
|
|
532
|
+
console.log(`Last activity: ${session.lastActivityType}`);
|
|
533
|
+
if (session.lastActivityAt)
|
|
534
|
+
console.log(`Last updated: ${session.lastActivityAt}`);
|
|
535
|
+
if (session.summary) {
|
|
536
|
+
console.log(`\nSummary:\n ${session.summary.replace(/\n/g, '\n ')}`);
|
|
537
|
+
}
|
|
538
|
+
if (session.lastActivityContent && session.lastActivityContent !== session.summary) {
|
|
539
|
+
console.log(`\nLatest checkpoint:\n ${session.lastActivityContent.replace(/\n/g, '\n ')}`);
|
|
540
|
+
}
|
|
541
|
+
if (activities.length > 0) {
|
|
542
|
+
console.log('\nRecent activity:');
|
|
543
|
+
for (const activity of activities) {
|
|
544
|
+
const date = new Date(activity.createdAt ?? Date.now()).toISOString();
|
|
545
|
+
const actor = activity.actorName || activity.actorEmail || 'Unknown';
|
|
546
|
+
const content = activity.content || '';
|
|
547
|
+
console.log(` [${date}] ${activity.type} (${actor})`);
|
|
548
|
+
if (content)
|
|
549
|
+
console.log(` ${content.replace(/\n/g, '\n ')}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
console.log('\nNo session activity found.');
|
|
554
|
+
}
|
|
555
|
+
console.log(`\nBTX_SESSION_JSON: ${sessionPayload(session)}`);
|
|
556
|
+
}
|
|
359
557
|
// ── Help ─────────────────────────────────────────────────────────────────────
|
|
360
558
|
const HELP = {
|
|
361
|
-
top: `BTX CLI - manage tasks, contacts, meetings, and leads from a session.
|
|
559
|
+
top: `BTX CLI - manage tasks, contacts, meetings, recordings, and leads from a session.
|
|
362
560
|
|
|
363
561
|
Usage:
|
|
364
562
|
node "$BTX_CLI_PATH" <resource> <command> [flags]
|
|
@@ -366,10 +564,11 @@ Usage:
|
|
|
366
564
|
|
|
367
565
|
Resources:
|
|
368
566
|
tasks Create and manage project tasks
|
|
369
|
-
sessions
|
|
567
|
+
sessions Browse recent sessions, inspect summaries, add notes
|
|
370
568
|
contacts View and update contacts, add notes
|
|
371
569
|
orgs View organizations, add notes
|
|
372
570
|
meetings View meeting recordings and transcripts
|
|
571
|
+
recordings View recording imports and transcripts
|
|
373
572
|
leads List lead types
|
|
374
573
|
user Manage your profile notes
|
|
375
574
|
intro-paths Find warm intro paths in your network
|
|
@@ -380,8 +579,10 @@ Resources:
|
|
|
380
579
|
Examples:
|
|
381
580
|
node "$BTX_CLI_PATH" tasks list --status todo
|
|
382
581
|
node "$BTX_CLI_PATH" tasks list --json
|
|
582
|
+
node "$BTX_CLI_PATH" recordings list --days 7
|
|
583
|
+
node "$BTX_CLI_PATH" recordings transcript <recording-id>
|
|
383
584
|
node "$BTX_CLI_PATH" meetings list --days 7
|
|
384
|
-
node "$BTX_CLI_PATH" meetings
|
|
585
|
+
node "$BTX_CLI_PATH" meetings transcript <meeting-id>
|
|
385
586
|
node "$BTX_CLI_PATH" contacts --help
|
|
386
587
|
|
|
387
588
|
All resource commands support --json for machine-readable output.`,
|
|
@@ -417,16 +618,24 @@ Examples:
|
|
|
417
618
|
node "$BTX_CLI_PATH" tasks complete abc123
|
|
418
619
|
node "$BTX_CLI_PATH" tasks notes list abc123
|
|
419
620
|
node "$BTX_CLI_PATH" tasks notes add abc123 --content "Insight: ICP may be wrong on stage" --source "https://..."`,
|
|
420
|
-
sessions: `BTX sessions -
|
|
621
|
+
sessions: `BTX sessions - browse recent sessions and inspect a session's checkpoints.
|
|
421
622
|
|
|
422
623
|
Commands:
|
|
624
|
+
list List recent sessions (metadata only)
|
|
625
|
+
get <session-id> Get one session with recent checkpoints
|
|
423
626
|
notes list <session-id> List notes for a session
|
|
424
627
|
notes add <session-id> --content "..." Add a note to a session
|
|
425
628
|
|
|
426
629
|
Flags:
|
|
630
|
+
sessions list [--status open|closed] [--type <session-type>] [--runtime <runtime>] [--query "text"] [--limit <n>]
|
|
631
|
+
sessions get <session-id> [--activity-limit <n>]
|
|
427
632
|
sessions notes add <session-id> --content "Label: value" [--source "https://..."]
|
|
428
633
|
|
|
429
634
|
Examples:
|
|
635
|
+
node "$BTX_CLI_PATH" sessions list --limit 10
|
|
636
|
+
node "$BTX_CLI_PATH" sessions list --status closed --query "auth"
|
|
637
|
+
node "$BTX_CLI_PATH" sessions get abc-session-id
|
|
638
|
+
node "$BTX_CLI_PATH" sessions get abc-session-id --activity-limit 10
|
|
430
639
|
node "$BTX_CLI_PATH" sessions notes list abc-session-id
|
|
431
640
|
node "$BTX_CLI_PATH" sessions notes add abc-session-id --content "Insight: market timing is critical"
|
|
432
641
|
node "$BTX_CLI_PATH" sessions notes add abc-session-id --content "Decision: pivot to enterprise" --source "https://..."`,
|
|
@@ -547,6 +756,27 @@ Examples:
|
|
|
547
756
|
node "$BTX_CLI_PATH" meetings list --query "onboarding"
|
|
548
757
|
node "$BTX_CLI_PATH" meetings get abc123
|
|
549
758
|
node "$BTX_CLI_PATH" meetings transcript abc123`,
|
|
759
|
+
recordings: `BTX recordings - view synced recordings and transcripts.
|
|
760
|
+
|
|
761
|
+
Commands:
|
|
762
|
+
list List recordings (filterable by date, source, status)
|
|
763
|
+
get Get recording details
|
|
764
|
+
transcript Get the full transcript for a recording
|
|
765
|
+
|
|
766
|
+
Flags:
|
|
767
|
+
recordings list [--days <n>] [--query "text"] [--status <status>] [--source <source>]
|
|
768
|
+
recordings get <recording-id>
|
|
769
|
+
recordings transcript <recording-id>
|
|
770
|
+
|
|
771
|
+
The --days flag filters to recordings from the last N days (default: all).
|
|
772
|
+
Use "list" to browse imported or uploaded recordings, "get" for metadata,
|
|
773
|
+
and "transcript" for the transcript text coding agents can consume directly.
|
|
774
|
+
|
|
775
|
+
Examples:
|
|
776
|
+
node "$BTX_CLI_PATH" recordings list
|
|
777
|
+
node "$BTX_CLI_PATH" recordings list --days 7
|
|
778
|
+
node "$BTX_CLI_PATH" recordings list --source granola
|
|
779
|
+
node "$BTX_CLI_PATH" recordings transcript abc123`,
|
|
550
780
|
context: `BTX context - fetch the current project business context.
|
|
551
781
|
|
|
552
782
|
Commands:
|
|
@@ -1144,6 +1374,69 @@ async function taskNotesList(taskId, flags) {
|
|
|
1144
1374
|
}
|
|
1145
1375
|
}
|
|
1146
1376
|
// ── Session notes commands ────────────────────────────────────────────────────
|
|
1377
|
+
async function fetchSessions(flags) {
|
|
1378
|
+
const params = new URLSearchParams();
|
|
1379
|
+
if (flags.status)
|
|
1380
|
+
params.set('status', flags.status);
|
|
1381
|
+
if (flags.type)
|
|
1382
|
+
params.set('session_type', flags.type);
|
|
1383
|
+
params.set('limit', String(readIntFlag(flags, 'limit', 20)));
|
|
1384
|
+
const suffix = params.toString();
|
|
1385
|
+
const result = await api('GET', `/sessions${suffix ? `?${suffix}` : ''}`);
|
|
1386
|
+
let sessions = result.sessions ?? [];
|
|
1387
|
+
if (flags.runtime) {
|
|
1388
|
+
const runtime = flags.runtime.toLowerCase();
|
|
1389
|
+
sessions = sessions.filter((session) => (session.runtime || '').toLowerCase().includes(runtime));
|
|
1390
|
+
}
|
|
1391
|
+
if (flags.query) {
|
|
1392
|
+
const query = flags.query.toLowerCase();
|
|
1393
|
+
sessions = sessions.filter((session) => {
|
|
1394
|
+
const haystack = [
|
|
1395
|
+
session.label,
|
|
1396
|
+
session.summary,
|
|
1397
|
+
session.lastActivityContent,
|
|
1398
|
+
session.sessionType,
|
|
1399
|
+
session.runtime,
|
|
1400
|
+
session.userName,
|
|
1401
|
+
session.userEmail,
|
|
1402
|
+
]
|
|
1403
|
+
.filter(Boolean)
|
|
1404
|
+
.join('\n')
|
|
1405
|
+
.toLowerCase();
|
|
1406
|
+
return haystack.includes(query);
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
return sessions;
|
|
1410
|
+
}
|
|
1411
|
+
async function fetchSession(sessionId) {
|
|
1412
|
+
const result = await api('GET', `/sessions/${encodeURIComponent(sessionId)}`);
|
|
1413
|
+
return result.session ?? null;
|
|
1414
|
+
}
|
|
1415
|
+
async function fetchSessionActivities(sessionId, limit) {
|
|
1416
|
+
const result = await api('GET', `/session-activities?sessionId=${encodeURIComponent(sessionId)}&limit=${limit}`);
|
|
1417
|
+
return Array.isArray(result) ? result : [];
|
|
1418
|
+
}
|
|
1419
|
+
async function sessionsList(flags) {
|
|
1420
|
+
const sessions = await fetchSessions(flags);
|
|
1421
|
+
if (isJson(flags)) {
|
|
1422
|
+
printJson(sessions);
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
formatSessionTable(sessions);
|
|
1426
|
+
}
|
|
1427
|
+
async function sessionsGet(sessionId, flags) {
|
|
1428
|
+
if (!sessionId)
|
|
1429
|
+
die('Usage: btx sessions get <session-id> [--activity-limit <n>]');
|
|
1430
|
+
const session = await fetchSession(sessionId);
|
|
1431
|
+
if (!session)
|
|
1432
|
+
die(`Session not found: ${sessionId}`);
|
|
1433
|
+
const activities = await fetchSessionActivities(sessionId, readIntFlag(flags, 'activity-limit', 10, 1, 50));
|
|
1434
|
+
if (isJson(flags)) {
|
|
1435
|
+
printJson({ session, activities });
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
formatSessionDetail(session, activities);
|
|
1439
|
+
}
|
|
1147
1440
|
async function sessionNotesAdd(sessionId, flags) {
|
|
1148
1441
|
if (!sessionId)
|
|
1149
1442
|
die('Usage: btx sessions notes add <session-id> --content "..."');
|
|
@@ -1328,11 +1621,13 @@ async function globalSearch(flags) {
|
|
|
1328
1621
|
}
|
|
1329
1622
|
if (matches.length === 0) {
|
|
1330
1623
|
console.log(`No tasks found matching "${query}".`);
|
|
1331
|
-
console.log('\
|
|
1624
|
+
console.log('\nFor recent coding context, use `node "$BTX_CLI_PATH" sessions list --limit 10`.');
|
|
1625
|
+
console.log('For full-text transcript search, use Cmd+Shift+F in the BTX app.');
|
|
1332
1626
|
return;
|
|
1333
1627
|
}
|
|
1334
1628
|
formatTaskTable(matches);
|
|
1335
|
-
console.log('\
|
|
1629
|
+
console.log('\nFor recent coding context, use `node "$BTX_CLI_PATH" sessions list --limit 10`.');
|
|
1630
|
+
console.log('For full-text transcript search, use Cmd+Shift+F in the BTX app.');
|
|
1336
1631
|
}
|
|
1337
1632
|
// ── User profile notes commands ───────────────────────────────────────────────
|
|
1338
1633
|
async function userNotesAdd(flags) {
|
|
@@ -1796,6 +2091,10 @@ async function fetchMeetings() {
|
|
|
1796
2091
|
const result = await api('GET', '/meetings');
|
|
1797
2092
|
return result?.meetings ?? [];
|
|
1798
2093
|
}
|
|
2094
|
+
async function fetchRecordings() {
|
|
2095
|
+
const result = await api('GET', '/recordings');
|
|
2096
|
+
return result?.recordings ?? [];
|
|
2097
|
+
}
|
|
1799
2098
|
async function meetingsList(flags) {
|
|
1800
2099
|
let meetings = await fetchMeetings();
|
|
1801
2100
|
if (flags.days) {
|
|
@@ -1842,6 +2141,71 @@ async function meetingsTranscript(id, flags) {
|
|
|
1842
2141
|
}
|
|
1843
2142
|
formatMeetingTranscript(meeting);
|
|
1844
2143
|
}
|
|
2144
|
+
async function recordingsList(flags) {
|
|
2145
|
+
let recordings = await fetchRecordings();
|
|
2146
|
+
if (flags.days) {
|
|
2147
|
+
const cutoff = new Date();
|
|
2148
|
+
cutoff.setDate(cutoff.getDate() - Number(flags.days));
|
|
2149
|
+
const cutoffStr = cutoff.toISOString();
|
|
2150
|
+
recordings = recordings.filter((recording) => {
|
|
2151
|
+
const timestamp = recordingTimestamp(recording);
|
|
2152
|
+
return timestamp != null && timestamp >= cutoffStr;
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
if (flags.status) {
|
|
2156
|
+
const expected = flags.status.toLowerCase();
|
|
2157
|
+
recordings = recordings.filter((recording) => (recording.status || '').toLowerCase() === expected);
|
|
2158
|
+
}
|
|
2159
|
+
if (flags.source) {
|
|
2160
|
+
const expected = flags.source.toLowerCase();
|
|
2161
|
+
recordings = recordings.filter((recording) => (recording.source || '').toLowerCase() === expected);
|
|
2162
|
+
}
|
|
2163
|
+
if (flags.query) {
|
|
2164
|
+
const q = flags.query.toLowerCase();
|
|
2165
|
+
recordings = recordings.filter((recording) => recordingTitle(recording).toLowerCase().includes(q) ||
|
|
2166
|
+
(recording.originalFilename || '').toLowerCase().includes(q) ||
|
|
2167
|
+
(recording.transcriptText || '').toLowerCase().includes(q) ||
|
|
2168
|
+
(recording.source || '').toLowerCase().includes(q) ||
|
|
2169
|
+
(recording.status || '').toLowerCase().includes(q));
|
|
2170
|
+
}
|
|
2171
|
+
if (isJson(flags)) {
|
|
2172
|
+
printJson(recordings);
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
formatRecordingTable(recordings);
|
|
2176
|
+
}
|
|
2177
|
+
async function recordingsGet(id, flags) {
|
|
2178
|
+
if (!id)
|
|
2179
|
+
die('Usage: btx recordings get <recording-id>');
|
|
2180
|
+
const recordings = await fetchRecordings();
|
|
2181
|
+
const recording = recordings.find((item) => item.id === id);
|
|
2182
|
+
if (!recording)
|
|
2183
|
+
die(`Recording not found: ${id}`);
|
|
2184
|
+
if (isJson(flags)) {
|
|
2185
|
+
printJson(recording);
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
formatRecordingDetail(recording);
|
|
2189
|
+
}
|
|
2190
|
+
async function recordingsTranscript(id, flags) {
|
|
2191
|
+
if (!id)
|
|
2192
|
+
die('Usage: btx recordings transcript <recording-id>');
|
|
2193
|
+
const recordings = await fetchRecordings();
|
|
2194
|
+
const recording = recordings.find((item) => item.id === id);
|
|
2195
|
+
if (!recording)
|
|
2196
|
+
die(`Recording not found: ${id}`);
|
|
2197
|
+
if (isJson(flags)) {
|
|
2198
|
+
printJson({
|
|
2199
|
+
id: recording.id,
|
|
2200
|
+
meetingId: recording.meetingId ?? null,
|
|
2201
|
+
title: recordingTitle(recording),
|
|
2202
|
+
transcriptText: recording.transcriptText ?? '',
|
|
2203
|
+
transcript: recording.transcript ?? [],
|
|
2204
|
+
});
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
formatRecordingTranscript(recording);
|
|
2208
|
+
}
|
|
1845
2209
|
// ── Main ────────────────────────────────────────────────────────────────────
|
|
1846
2210
|
export async function runRuntimeCli(args, env = process.env) {
|
|
1847
2211
|
configureRuntime(env);
|
|
@@ -1862,6 +2226,7 @@ export async function runRuntimeCli(args, env = process.env) {
|
|
|
1862
2226
|
'contacts',
|
|
1863
2227
|
'orgs',
|
|
1864
2228
|
'meetings',
|
|
2229
|
+
'recordings',
|
|
1865
2230
|
'leads',
|
|
1866
2231
|
'user',
|
|
1867
2232
|
'intro-paths',
|
|
@@ -1923,7 +2288,14 @@ export async function runRuntimeCli(args, env = process.env) {
|
|
|
1923
2288
|
die(`Unknown sessions notes command: "${subCommand || '(none)'}". Run: node "$BTX_CLI_PATH" sessions --help`);
|
|
1924
2289
|
}
|
|
1925
2290
|
}
|
|
1926
|
-
|
|
2291
|
+
switch (command) {
|
|
2292
|
+
case 'list':
|
|
2293
|
+
return sessionsList(flags);
|
|
2294
|
+
case 'get':
|
|
2295
|
+
return sessionsGet(positional[2], flags);
|
|
2296
|
+
default:
|
|
2297
|
+
die(`Unknown sessions command: "${command || '(none)'}". Run: node "$BTX_CLI_PATH" sessions --help`);
|
|
2298
|
+
}
|
|
1927
2299
|
}
|
|
1928
2300
|
else if (resource === 'contacts') {
|
|
1929
2301
|
if (command === 'notes') {
|
|
@@ -1997,6 +2369,18 @@ export async function runRuntimeCli(args, env = process.env) {
|
|
|
1997
2369
|
die(`Unknown meetings command: "${command || '(none)'}". Run: node "$BTX_CLI_PATH" meetings --help`);
|
|
1998
2370
|
}
|
|
1999
2371
|
}
|
|
2372
|
+
else if (resource === 'recordings') {
|
|
2373
|
+
switch (command) {
|
|
2374
|
+
case 'list':
|
|
2375
|
+
return recordingsList(flags);
|
|
2376
|
+
case 'get':
|
|
2377
|
+
return recordingsGet(positional[2], flags);
|
|
2378
|
+
case 'transcript':
|
|
2379
|
+
return recordingsTranscript(positional[2], flags);
|
|
2380
|
+
default:
|
|
2381
|
+
die(`Unknown recordings command: "${command || '(none)'}". Run: node "$BTX_CLI_PATH" recordings --help`);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2000
2384
|
else if (resource === 'intro-paths') {
|
|
2001
2385
|
switch (command) {
|
|
2002
2386
|
case 'find':
|