@secondcontext/btx-cli 0.0.2 → 0.0.5
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 +14 -8
- package/dist/bin.js +410 -13
- 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/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +41 -3
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +2 -1
- 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 +182 -5
- 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":"AAmNA,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;AAgvED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,GAAE,aAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC,CAiRf"}
|
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,6 +365,94 @@ function formatMeetingTranscript(m) {
|
|
|
356
365
|
console.log(`[${time}] ${speaker}: ${seg.text}`);
|
|
357
366
|
}
|
|
358
367
|
}
|
|
368
|
+
function sessionPayload(s) {
|
|
369
|
+
return JSON.stringify({
|
|
370
|
+
sessionId: s.sessionId,
|
|
371
|
+
label: s.label,
|
|
372
|
+
sessionType: s.sessionType,
|
|
373
|
+
runtime: s.runtime || null,
|
|
374
|
+
status: s.status,
|
|
375
|
+
messageCount: s.messageCount ?? 0,
|
|
376
|
+
activityCount: s.activityCount ?? 0,
|
|
377
|
+
summary: s.summary ?? null,
|
|
378
|
+
lastActivityType: s.lastActivityType ?? null,
|
|
379
|
+
lastActivityContent: s.lastActivityContent ?? null,
|
|
380
|
+
createdAt: typeof s.createdAt === 'number'
|
|
381
|
+
? new Date(s.createdAt).toISOString()
|
|
382
|
+
: s.createdAt,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
function sessionPreview(session) {
|
|
386
|
+
return session.summary || session.lastActivityContent || '';
|
|
387
|
+
}
|
|
388
|
+
function formatSessionTable(sessions) {
|
|
389
|
+
if (sessions.length === 0) {
|
|
390
|
+
console.log('No sessions found.');
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const idW = 12;
|
|
394
|
+
const dateW = 10;
|
|
395
|
+
const statusW = 8;
|
|
396
|
+
const typeW = 14;
|
|
397
|
+
const runtimeW = 12;
|
|
398
|
+
const labelW = 28;
|
|
399
|
+
console.log(`${padRight('ID', idW)} ${padRight('Date', dateW)} ${padRight('Status', statusW)} ${padRight('Type', typeW)} ${padRight('Runtime', runtimeW)} ${padRight('Label', labelW)} Preview`);
|
|
400
|
+
console.log(`${'\u2500'.repeat(idW)} ${'\u2500'.repeat(dateW)} ${'\u2500'.repeat(statusW)} ${'\u2500'.repeat(typeW)} ${'\u2500'.repeat(runtimeW)} ${'\u2500'.repeat(labelW)} ${'\u2500'.repeat(36)}`);
|
|
401
|
+
for (const session of sessions) {
|
|
402
|
+
const created = new Date(session.createdAt).toISOString().slice(0, 10);
|
|
403
|
+
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)}`);
|
|
404
|
+
}
|
|
405
|
+
console.log(`\n${sessions.length} session${sessions.length !== 1 ? 's' : ''} found`);
|
|
406
|
+
console.log('Use `btx sessions get <session-id>` for full details and recent checkpoints.');
|
|
407
|
+
for (const session of sessions) {
|
|
408
|
+
console.log(`BTX_SESSION_JSON: ${sessionPayload(session)}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function formatSessionDetail(session, activities) {
|
|
412
|
+
console.log(`Session: ${session.label}`);
|
|
413
|
+
console.log(`ID: ${session.sessionId}`);
|
|
414
|
+
console.log(`Status: ${session.status}`);
|
|
415
|
+
console.log(`Type: ${session.sessionType}`);
|
|
416
|
+
console.log(`Runtime: ${session.runtime || 'n/a'}`);
|
|
417
|
+
console.log(`Execution: ${session.executionMode}`);
|
|
418
|
+
console.log(`Started: ${new Date(session.createdAt).toISOString()}`);
|
|
419
|
+
if (session.updatedAt)
|
|
420
|
+
console.log(`Updated: ${new Date(session.updatedAt).toISOString()}`);
|
|
421
|
+
if (session.closedAt)
|
|
422
|
+
console.log(`Closed: ${session.closedAt}`);
|
|
423
|
+
if (session.userName || session.userEmail) {
|
|
424
|
+
console.log(`Owner: ${session.userName || session.userEmail}`);
|
|
425
|
+
}
|
|
426
|
+
console.log(`Messages: ${session.messageCount ?? 0}`);
|
|
427
|
+
console.log(`Activities: ${session.activityCount ?? 0}`);
|
|
428
|
+
if (session.totalCostUsd != null)
|
|
429
|
+
console.log(`Cost USD: ${session.totalCostUsd}`);
|
|
430
|
+
if (session.lastActivityType)
|
|
431
|
+
console.log(`Last activity: ${session.lastActivityType}`);
|
|
432
|
+
if (session.lastActivityAt)
|
|
433
|
+
console.log(`Last updated: ${session.lastActivityAt}`);
|
|
434
|
+
if (session.summary) {
|
|
435
|
+
console.log(`\nSummary:\n ${session.summary.replace(/\n/g, '\n ')}`);
|
|
436
|
+
}
|
|
437
|
+
if (session.lastActivityContent && session.lastActivityContent !== session.summary) {
|
|
438
|
+
console.log(`\nLatest checkpoint:\n ${session.lastActivityContent.replace(/\n/g, '\n ')}`);
|
|
439
|
+
}
|
|
440
|
+
if (activities.length > 0) {
|
|
441
|
+
console.log('\nRecent activity:');
|
|
442
|
+
for (const activity of activities) {
|
|
443
|
+
const date = new Date(activity.createdAt ?? Date.now()).toISOString();
|
|
444
|
+
const actor = activity.actorName || activity.actorEmail || 'Unknown';
|
|
445
|
+
const content = activity.content || '';
|
|
446
|
+
console.log(` [${date}] ${activity.type} (${actor})`);
|
|
447
|
+
if (content)
|
|
448
|
+
console.log(` ${content.replace(/\n/g, '\n ')}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
console.log('\nNo session activity found.');
|
|
453
|
+
}
|
|
454
|
+
console.log(`\nBTX_SESSION_JSON: ${sessionPayload(session)}`);
|
|
455
|
+
}
|
|
359
456
|
// ── Help ─────────────────────────────────────────────────────────────────────
|
|
360
457
|
const HELP = {
|
|
361
458
|
top: `BTX CLI - manage tasks, contacts, meetings, and leads from a session.
|
|
@@ -366,7 +463,7 @@ Usage:
|
|
|
366
463
|
|
|
367
464
|
Resources:
|
|
368
465
|
tasks Create and manage project tasks
|
|
369
|
-
sessions
|
|
466
|
+
sessions Browse recent sessions, inspect summaries, add notes
|
|
370
467
|
contacts View and update contacts, add notes
|
|
371
468
|
orgs View organizations, add notes
|
|
372
469
|
meetings View meeting recordings and transcripts
|
|
@@ -417,16 +514,24 @@ Examples:
|
|
|
417
514
|
node "$BTX_CLI_PATH" tasks complete abc123
|
|
418
515
|
node "$BTX_CLI_PATH" tasks notes list abc123
|
|
419
516
|
node "$BTX_CLI_PATH" tasks notes add abc123 --content "Insight: ICP may be wrong on stage" --source "https://..."`,
|
|
420
|
-
sessions: `BTX sessions -
|
|
517
|
+
sessions: `BTX sessions - browse recent sessions and inspect a session's checkpoints.
|
|
421
518
|
|
|
422
519
|
Commands:
|
|
520
|
+
list List recent sessions (metadata only)
|
|
521
|
+
get <session-id> Get one session with recent checkpoints
|
|
423
522
|
notes list <session-id> List notes for a session
|
|
424
523
|
notes add <session-id> --content "..." Add a note to a session
|
|
425
524
|
|
|
426
525
|
Flags:
|
|
526
|
+
sessions list [--status open|closed] [--type <session-type>] [--runtime <runtime>] [--query "text"] [--limit <n>]
|
|
527
|
+
sessions get <session-id> [--activity-limit <n>]
|
|
427
528
|
sessions notes add <session-id> --content "Label: value" [--source "https://..."]
|
|
428
529
|
|
|
429
530
|
Examples:
|
|
531
|
+
node "$BTX_CLI_PATH" sessions list --limit 10
|
|
532
|
+
node "$BTX_CLI_PATH" sessions list --status closed --query "auth"
|
|
533
|
+
node "$BTX_CLI_PATH" sessions get abc-session-id
|
|
534
|
+
node "$BTX_CLI_PATH" sessions get abc-session-id --activity-limit 10
|
|
430
535
|
node "$BTX_CLI_PATH" sessions notes list abc-session-id
|
|
431
536
|
node "$BTX_CLI_PATH" sessions notes add abc-session-id --content "Insight: market timing is critical"
|
|
432
537
|
node "$BTX_CLI_PATH" sessions notes add abc-session-id --content "Decision: pivot to enterprise" --source "https://..."`,
|
|
@@ -1144,6 +1249,69 @@ async function taskNotesList(taskId, flags) {
|
|
|
1144
1249
|
}
|
|
1145
1250
|
}
|
|
1146
1251
|
// ── Session notes commands ────────────────────────────────────────────────────
|
|
1252
|
+
async function fetchSessions(flags) {
|
|
1253
|
+
const params = new URLSearchParams();
|
|
1254
|
+
if (flags.status)
|
|
1255
|
+
params.set('status', flags.status);
|
|
1256
|
+
if (flags.type)
|
|
1257
|
+
params.set('session_type', flags.type);
|
|
1258
|
+
params.set('limit', String(readIntFlag(flags, 'limit', 20)));
|
|
1259
|
+
const suffix = params.toString();
|
|
1260
|
+
const result = await api('GET', `/sessions${suffix ? `?${suffix}` : ''}`);
|
|
1261
|
+
let sessions = result.sessions ?? [];
|
|
1262
|
+
if (flags.runtime) {
|
|
1263
|
+
const runtime = flags.runtime.toLowerCase();
|
|
1264
|
+
sessions = sessions.filter((session) => (session.runtime || '').toLowerCase().includes(runtime));
|
|
1265
|
+
}
|
|
1266
|
+
if (flags.query) {
|
|
1267
|
+
const query = flags.query.toLowerCase();
|
|
1268
|
+
sessions = sessions.filter((session) => {
|
|
1269
|
+
const haystack = [
|
|
1270
|
+
session.label,
|
|
1271
|
+
session.summary,
|
|
1272
|
+
session.lastActivityContent,
|
|
1273
|
+
session.sessionType,
|
|
1274
|
+
session.runtime,
|
|
1275
|
+
session.userName,
|
|
1276
|
+
session.userEmail,
|
|
1277
|
+
]
|
|
1278
|
+
.filter(Boolean)
|
|
1279
|
+
.join('\n')
|
|
1280
|
+
.toLowerCase();
|
|
1281
|
+
return haystack.includes(query);
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
return sessions;
|
|
1285
|
+
}
|
|
1286
|
+
async function fetchSession(sessionId) {
|
|
1287
|
+
const result = await api('GET', `/sessions?sessionId=${encodeURIComponent(sessionId)}`);
|
|
1288
|
+
return result.session ?? null;
|
|
1289
|
+
}
|
|
1290
|
+
async function fetchSessionActivities(sessionId, limit) {
|
|
1291
|
+
const result = await api('GET', `/session-activities?sessionId=${encodeURIComponent(sessionId)}&limit=${limit}`);
|
|
1292
|
+
return Array.isArray(result) ? result : [];
|
|
1293
|
+
}
|
|
1294
|
+
async function sessionsList(flags) {
|
|
1295
|
+
const sessions = await fetchSessions(flags);
|
|
1296
|
+
if (isJson(flags)) {
|
|
1297
|
+
printJson(sessions);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
formatSessionTable(sessions);
|
|
1301
|
+
}
|
|
1302
|
+
async function sessionsGet(sessionId, flags) {
|
|
1303
|
+
if (!sessionId)
|
|
1304
|
+
die('Usage: btx sessions get <session-id> [--activity-limit <n>]');
|
|
1305
|
+
const session = await fetchSession(sessionId);
|
|
1306
|
+
if (!session)
|
|
1307
|
+
die(`Session not found: ${sessionId}`);
|
|
1308
|
+
const activities = await fetchSessionActivities(sessionId, readIntFlag(flags, 'activity-limit', 10, 1, 50));
|
|
1309
|
+
if (isJson(flags)) {
|
|
1310
|
+
printJson({ session, activities });
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
formatSessionDetail(session, activities);
|
|
1314
|
+
}
|
|
1147
1315
|
async function sessionNotesAdd(sessionId, flags) {
|
|
1148
1316
|
if (!sessionId)
|
|
1149
1317
|
die('Usage: btx sessions notes add <session-id> --content "..."');
|
|
@@ -1328,11 +1496,13 @@ async function globalSearch(flags) {
|
|
|
1328
1496
|
}
|
|
1329
1497
|
if (matches.length === 0) {
|
|
1330
1498
|
console.log(`No tasks found matching "${query}".`);
|
|
1331
|
-
console.log('\
|
|
1499
|
+
console.log('\nFor recent coding context, use `node "$BTX_CLI_PATH" sessions list --limit 10`.');
|
|
1500
|
+
console.log('For full-text transcript search, use Cmd+Shift+F in the BTX app.');
|
|
1332
1501
|
return;
|
|
1333
1502
|
}
|
|
1334
1503
|
formatTaskTable(matches);
|
|
1335
|
-
console.log('\
|
|
1504
|
+
console.log('\nFor recent coding context, use `node "$BTX_CLI_PATH" sessions list --limit 10`.');
|
|
1505
|
+
console.log('For full-text transcript search, use Cmd+Shift+F in the BTX app.');
|
|
1336
1506
|
}
|
|
1337
1507
|
// ── User profile notes commands ───────────────────────────────────────────────
|
|
1338
1508
|
async function userNotesAdd(flags) {
|
|
@@ -1923,7 +2093,14 @@ export async function runRuntimeCli(args, env = process.env) {
|
|
|
1923
2093
|
die(`Unknown sessions notes command: "${subCommand || '(none)'}". Run: node "$BTX_CLI_PATH" sessions --help`);
|
|
1924
2094
|
}
|
|
1925
2095
|
}
|
|
1926
|
-
|
|
2096
|
+
switch (command) {
|
|
2097
|
+
case 'list':
|
|
2098
|
+
return sessionsList(flags);
|
|
2099
|
+
case 'get':
|
|
2100
|
+
return sessionsGet(positional[2], flags);
|
|
2101
|
+
default:
|
|
2102
|
+
die(`Unknown sessions command: "${command || '(none)'}". Run: node "$BTX_CLI_PATH" sessions --help`);
|
|
2103
|
+
}
|
|
1927
2104
|
}
|
|
1928
2105
|
else if (resource === 'contacts') {
|
|
1929
2106
|
if (command === 'notes') {
|