@fluxra-ai/fluxra-cli 0.1.0
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/LICENSE +201 -0
- package/README.md +274 -0
- package/bin/fluxra +6 -0
- package/dist/cli/command-context.d.ts +17 -0
- package/dist/cli/command-context.d.ts.map +1 -0
- package/dist/cli/command-context.js +26 -0
- package/dist/cli/command-context.js.map +1 -0
- package/dist/cli/commands/auth/index.d.ts +3 -0
- package/dist/cli/commands/auth/index.d.ts.map +1 -0
- package/dist/cli/commands/auth/index.js +165 -0
- package/dist/cli/commands/auth/index.js.map +1 -0
- package/dist/cli/commands/chat/index.d.ts +3 -0
- package/dist/cli/commands/chat/index.d.ts.map +1 -0
- package/dist/cli/commands/chat/index.js +1201 -0
- package/dist/cli/commands/chat/index.js.map +1 -0
- package/dist/cli/commands/config/index.d.ts +3 -0
- package/dist/cli/commands/config/index.d.ts.map +1 -0
- package/dist/cli/commands/config/index.js +66 -0
- package/dist/cli/commands/config/index.js.map +1 -0
- package/dist/cli/commands/help.d.ts +7 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +106 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/local/doctor.d.ts +26 -0
- package/dist/cli/commands/local/doctor.d.ts.map +1 -0
- package/dist/cli/commands/local/doctor.js +265 -0
- package/dist/cli/commands/local/doctor.js.map +1 -0
- package/dist/cli/commands/local/export.d.ts +41 -0
- package/dist/cli/commands/local/export.d.ts.map +1 -0
- package/dist/cli/commands/local/export.js +83 -0
- package/dist/cli/commands/local/export.js.map +1 -0
- package/dist/cli/commands/local/index.d.ts +6 -0
- package/dist/cli/commands/local/index.d.ts.map +1 -0
- package/dist/cli/commands/local/index.js +116 -0
- package/dist/cli/commands/local/index.js.map +1 -0
- package/dist/cli/commands/local/inspect.d.ts +42 -0
- package/dist/cli/commands/local/inspect.d.ts.map +1 -0
- package/dist/cli/commands/local/inspect.js +125 -0
- package/dist/cli/commands/local/inspect.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +8 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +253 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/profile/index.d.ts +3 -0
- package/dist/cli/commands/profile/index.d.ts.map +1 -0
- package/dist/cli/commands/profile/index.js +114 -0
- package/dist/cli/commands/profile/index.js.map +1 -0
- package/dist/cli/commands/schema.d.ts +7 -0
- package/dist/cli/commands/schema.d.ts.map +1 -0
- package/dist/cli/commands/schema.js +33 -0
- package/dist/cli/commands/schema.js.map +1 -0
- package/dist/cli/errors.d.ts +16 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +15 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/fluxra.d.ts +9 -0
- package/dist/cli/fluxra.d.ts.map +1 -0
- package/dist/cli/fluxra.js +55 -0
- package/dist/cli/fluxra.js.map +1 -0
- package/dist/cli/helpers.d.ts +13 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +32 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/output.d.ts +14 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +55 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/version.d.ts +6 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +8 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/core/auth/auth-service.d.ts +35 -0
- package/dist/core/auth/auth-service.d.ts.map +1 -0
- package/dist/core/auth/auth-service.js +116 -0
- package/dist/core/auth/auth-service.js.map +1 -0
- package/dist/core/config/global-config.d.ts +38 -0
- package/dist/core/config/global-config.d.ts.map +1 -0
- package/dist/core/config/global-config.js +75 -0
- package/dist/core/config/global-config.js.map +1 -0
- package/dist/core/errors/error-model.d.ts +48 -0
- package/dist/core/errors/error-model.d.ts.map +1 -0
- package/dist/core/errors/error-model.js +152 -0
- package/dist/core/errors/error-model.js.map +1 -0
- package/dist/core/filesystem/paths.d.ts +45 -0
- package/dist/core/filesystem/paths.d.ts.map +1 -0
- package/dist/core/filesystem/paths.js +77 -0
- package/dist/core/filesystem/paths.js.map +1 -0
- package/dist/core/http/auth-api.d.ts +71 -0
- package/dist/core/http/auth-api.d.ts.map +1 -0
- package/dist/core/http/auth-api.js +91 -0
- package/dist/core/http/auth-api.js.map +1 -0
- package/dist/core/http/block-api.d.ts +37 -0
- package/dist/core/http/block-api.d.ts.map +1 -0
- package/dist/core/http/block-api.js +36 -0
- package/dist/core/http/block-api.js.map +1 -0
- package/dist/core/http/chat-api.d.ts +41 -0
- package/dist/core/http/chat-api.d.ts.map +1 -0
- package/dist/core/http/chat-api.js +88 -0
- package/dist/core/http/chat-api.js.map +1 -0
- package/dist/core/http/conversation-management-api.d.ts +65 -0
- package/dist/core/http/conversation-management-api.d.ts.map +1 -0
- package/dist/core/http/conversation-management-api.js +59 -0
- package/dist/core/http/conversation-management-api.js.map +1 -0
- package/dist/core/http/directory-api.d.ts +32 -0
- package/dist/core/http/directory-api.d.ts.map +1 -0
- package/dist/core/http/directory-api.js +36 -0
- package/dist/core/http/directory-api.js.map +1 -0
- package/dist/core/http/directory-profile-api.d.ts +32 -0
- package/dist/core/http/directory-profile-api.d.ts.map +1 -0
- package/dist/core/http/directory-profile-api.js +39 -0
- package/dist/core/http/directory-profile-api.js.map +1 -0
- package/dist/core/http/http-client.d.ts +41 -0
- package/dist/core/http/http-client.d.ts.map +1 -0
- package/dist/core/http/http-client.js +127 -0
- package/dist/core/http/http-client.js.map +1 -0
- package/dist/core/http/message-api.d.ts +55 -0
- package/dist/core/http/message-api.d.ts.map +1 -0
- package/dist/core/http/message-api.js +64 -0
- package/dist/core/http/message-api.js.map +1 -0
- package/dist/core/http/rate-limit.d.ts +22 -0
- package/dist/core/http/rate-limit.d.ts.map +1 -0
- package/dist/core/http/rate-limit.js +66 -0
- package/dist/core/http/rate-limit.js.map +1 -0
- package/dist/core/http/token-lifecycle.d.ts +18 -0
- package/dist/core/http/token-lifecycle.d.ts.map +1 -0
- package/dist/core/http/token-lifecycle.js +73 -0
- package/dist/core/http/token-lifecycle.js.map +1 -0
- package/dist/core/locking/profile-lock.d.ts +32 -0
- package/dist/core/locking/profile-lock.d.ts.map +1 -0
- package/dist/core/locking/profile-lock.js +104 -0
- package/dist/core/locking/profile-lock.js.map +1 -0
- package/dist/core/profiles/profile-service.d.ts +35 -0
- package/dist/core/profiles/profile-service.d.ts.map +1 -0
- package/dist/core/profiles/profile-service.js +119 -0
- package/dist/core/profiles/profile-service.js.map +1 -0
- package/dist/core/profiles/profile-types.d.ts +28 -0
- package/dist/core/profiles/profile-types.d.ts.map +1 -0
- package/dist/core/profiles/profile-types.js +13 -0
- package/dist/core/profiles/profile-types.js.map +1 -0
- package/dist/core/secrets/secrets-service.d.ts +25 -0
- package/dist/core/secrets/secrets-service.d.ts.map +1 -0
- package/dist/core/secrets/secrets-service.js +67 -0
- package/dist/core/secrets/secrets-service.js.map +1 -0
- package/dist/core/secrets/secrets-types.d.ts +29 -0
- package/dist/core/secrets/secrets-types.d.ts.map +1 -0
- package/dist/core/secrets/secrets-types.js +33 -0
- package/dist/core/secrets/secrets-types.js.map +1 -0
- package/dist/core/sqlite/chat-schema.d.ts +14 -0
- package/dist/core/sqlite/chat-schema.d.ts.map +1 -0
- package/dist/core/sqlite/chat-schema.js +172 -0
- package/dist/core/sqlite/chat-schema.js.map +1 -0
- package/dist/core/sqlite/core-schema.d.ts +14 -0
- package/dist/core/sqlite/core-schema.d.ts.map +1 -0
- package/dist/core/sqlite/core-schema.js +54 -0
- package/dist/core/sqlite/core-schema.js.map +1 -0
- package/dist/core/sqlite/database.d.ts +40 -0
- package/dist/core/sqlite/database.d.ts.map +1 -0
- package/dist/core/sqlite/database.js +68 -0
- package/dist/core/sqlite/database.js.map +1 -0
- package/dist/core/sqlite/migrations.d.ts +22 -0
- package/dist/core/sqlite/migrations.d.ts.map +1 -0
- package/dist/core/sqlite/migrations.js +64 -0
- package/dist/core/sqlite/migrations.js.map +1 -0
- package/dist/modules/chat/inbox/conversation-service.d.ts +35 -0
- package/dist/modules/chat/inbox/conversation-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/conversation-service.js +54 -0
- package/dist/modules/chat/inbox/conversation-service.js.map +1 -0
- package/dist/modules/chat/inbox/history-service.d.ts +25 -0
- package/dist/modules/chat/inbox/history-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/history-service.js +57 -0
- package/dist/modules/chat/inbox/history-service.js.map +1 -0
- package/dist/modules/chat/inbox/index.d.ts +9 -0
- package/dist/modules/chat/inbox/index.d.ts.map +1 -0
- package/dist/modules/chat/inbox/index.js +9 -0
- package/dist/modules/chat/inbox/index.js.map +1 -0
- package/dist/modules/chat/inbox/read-service.d.ts +36 -0
- package/dist/modules/chat/inbox/read-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/read-service.js +91 -0
- package/dist/modules/chat/inbox/read-service.js.map +1 -0
- package/dist/modules/chat/inbox/search-service.d.ts +20 -0
- package/dist/modules/chat/inbox/search-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/search-service.js +23 -0
- package/dist/modules/chat/inbox/search-service.js.map +1 -0
- package/dist/modules/chat/inbox/unread-service.d.ts +38 -0
- package/dist/modules/chat/inbox/unread-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/unread-service.js +65 -0
- package/dist/modules/chat/inbox/unread-service.js.map +1 -0
- package/dist/modules/chat/render/message-render.d.ts +35 -0
- package/dist/modules/chat/render/message-render.d.ts.map +1 -0
- package/dist/modules/chat/render/message-render.js +129 -0
- package/dist/modules/chat/render/message-render.js.map +1 -0
- package/dist/modules/chat/send/conversation-service.d.ts +53 -0
- package/dist/modules/chat/send/conversation-service.d.ts.map +1 -0
- package/dist/modules/chat/send/conversation-service.js +110 -0
- package/dist/modules/chat/send/conversation-service.js.map +1 -0
- package/dist/modules/chat/send/directory-cache-service.d.ts +37 -0
- package/dist/modules/chat/send/directory-cache-service.d.ts.map +1 -0
- package/dist/modules/chat/send/directory-cache-service.js +49 -0
- package/dist/modules/chat/send/directory-cache-service.js.map +1 -0
- package/dist/modules/chat/send/send-service.d.ts +36 -0
- package/dist/modules/chat/send/send-service.d.ts.map +1 -0
- package/dist/modules/chat/send/send-service.js +113 -0
- package/dist/modules/chat/send/send-service.js.map +1 -0
- package/dist/modules/chat/store/conversation-repo.d.ts +53 -0
- package/dist/modules/chat/store/conversation-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/conversation-repo.js +75 -0
- package/dist/modules/chat/store/conversation-repo.js.map +1 -0
- package/dist/modules/chat/store/directory-cache-repo.d.ts +41 -0
- package/dist/modules/chat/store/directory-cache-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/directory-cache-repo.js +64 -0
- package/dist/modules/chat/store/directory-cache-repo.js.map +1 -0
- package/dist/modules/chat/store/job-repo.d.ts +72 -0
- package/dist/modules/chat/store/job-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/job-repo.js +140 -0
- package/dist/modules/chat/store/job-repo.js.map +1 -0
- package/dist/modules/chat/store/message-repo.d.ts +98 -0
- package/dist/modules/chat/store/message-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/message-repo.js +231 -0
- package/dist/modules/chat/store/message-repo.js.map +1 -0
- package/dist/modules/chat/store/outbox-repo.d.ts +73 -0
- package/dist/modules/chat/store/outbox-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/outbox-repo.js +112 -0
- package/dist/modules/chat/store/outbox-repo.js.map +1 -0
- package/dist/modules/chat/store/read-state-repo.d.ts +83 -0
- package/dist/modules/chat/store/read-state-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/read-state-repo.js +210 -0
- package/dist/modules/chat/store/read-state-repo.js.map +1 -0
- package/dist/modules/chat/store/sync-state-repo.d.ts +45 -0
- package/dist/modules/chat/store/sync-state-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/sync-state-repo.js +67 -0
- package/dist/modules/chat/store/sync-state-repo.js.map +1 -0
- package/dist/modules/chat/sync/backfill.d.ts +13 -0
- package/dist/modules/chat/sync/backfill.d.ts.map +1 -0
- package/dist/modules/chat/sync/backfill.js +37 -0
- package/dist/modules/chat/sync/backfill.js.map +1 -0
- package/dist/modules/chat/sync/cron-manager.d.ts +50 -0
- package/dist/modules/chat/sync/cron-manager.d.ts.map +1 -0
- package/dist/modules/chat/sync/cron-manager.js +164 -0
- package/dist/modules/chat/sync/cron-manager.js.map +1 -0
- package/dist/modules/chat/sync/index.d.ts +8 -0
- package/dist/modules/chat/sync/index.d.ts.map +1 -0
- package/dist/modules/chat/sync/index.js +7 -0
- package/dist/modules/chat/sync/index.js.map +1 -0
- package/dist/modules/chat/sync/job-logger.d.ts +44 -0
- package/dist/modules/chat/sync/job-logger.d.ts.map +1 -0
- package/dist/modules/chat/sync/job-logger.js +139 -0
- package/dist/modules/chat/sync/job-logger.js.map +1 -0
- package/dist/modules/chat/sync/sync-service.d.ts +14 -0
- package/dist/modules/chat/sync/sync-service.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-service.js +174 -0
- package/dist/modules/chat/sync/sync-service.js.map +1 -0
- package/dist/modules/chat/sync/sync-status.d.ts +14 -0
- package/dist/modules/chat/sync/sync-status.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-status.js +77 -0
- package/dist/modules/chat/sync/sync-status.js.map +1 -0
- package/dist/modules/chat/sync/sync-types.d.ts +80 -0
- package/dist/modules/chat/sync/sync-types.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-types.js +5 -0
- package/dist/modules/chat/sync/sync-types.js.map +1 -0
- package/dist/modules/chat/sync/watch-mode.d.ts +45 -0
- package/dist/modules/chat/sync/watch-mode.d.ts.map +1 -0
- package/dist/modules/chat/sync/watch-mode.js +161 -0
- package/dist/modules/chat/sync/watch-mode.js.map +1 -0
- package/package.json +67 -0
- package/tool-schema.json +1039 -0
|
@@ -0,0 +1,1201 @@
|
|
|
1
|
+
import { resolveProfile } from '../../helpers.js';
|
|
2
|
+
import { openProfileDatabases, closeDatabases } from '../../command-context.js';
|
|
3
|
+
import { syncOnceLocked } from '../../../modules/chat/sync/sync-service.js';
|
|
4
|
+
import { getSyncStatus, formatSyncStatus } from '../../../modules/chat/sync/sync-status.js';
|
|
5
|
+
import { getUnreadSummaryData, getUnreadPreview } from '../../../modules/chat/inbox/unread-service.js';
|
|
6
|
+
import { readMessages } from '../../../modules/chat/inbox/read-service.js';
|
|
7
|
+
import { getHistory } from '../../../modules/chat/inbox/history-service.js';
|
|
8
|
+
import { searchLocalMessages } from '../../../modules/chat/inbox/search-service.js';
|
|
9
|
+
import { listConversationsWithUnread, getConversationDetail } from '../../../modules/chat/inbox/conversation-service.js';
|
|
10
|
+
import { sendMessage, editMessage, deleteMessage } from '../../../modules/chat/send/send-service.js';
|
|
11
|
+
import { createConversation, inviteMember, removeMember, updateRole, leaveConversation } from '../../../modules/chat/send/conversation-service.js';
|
|
12
|
+
import { renderMessageList } from '../../../modules/chat/render/message-render.js';
|
|
13
|
+
import { output, renderTable } from '../../output.js';
|
|
14
|
+
import { timeUntilNextPoll } from '../../../core/http/rate-limit.js';
|
|
15
|
+
import { ensureValidAccessToken } from '../../../core/http/token-lifecycle.js';
|
|
16
|
+
export function registerChatCommands(program) {
|
|
17
|
+
const chat = program.command('chat');
|
|
18
|
+
chat.description('Chat and messaging commands');
|
|
19
|
+
const sync = chat.command('sync');
|
|
20
|
+
sync.description('Chat synchronization commands');
|
|
21
|
+
sync
|
|
22
|
+
.command('once')
|
|
23
|
+
.description('Perform a one-shot sync')
|
|
24
|
+
.option('--profile <name>', 'Profile to use')
|
|
25
|
+
.option('--json', 'Output in JSON format')
|
|
26
|
+
.option('--force', 'Bypass rate limit check')
|
|
27
|
+
.option('--verbose', 'Show detailed progress')
|
|
28
|
+
.action(async (opts, command) => {
|
|
29
|
+
try {
|
|
30
|
+
const profileName = resolveProfile(opts, command);
|
|
31
|
+
if (!profileName) {
|
|
32
|
+
console.error('Error: No active profile. Use "fluxra profile use <name>"');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
36
|
+
try {
|
|
37
|
+
const report = await syncOnceLocked(coreDb, chatDb, profileName, {
|
|
38
|
+
force: opts.force,
|
|
39
|
+
verbose: opts.verbose,
|
|
40
|
+
});
|
|
41
|
+
if (opts.json) {
|
|
42
|
+
output(report, { json: true });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
if (report.success) {
|
|
46
|
+
console.log('✓ Sync complete');
|
|
47
|
+
console.log(` Messages fetched: ${report.messagesFetched}`);
|
|
48
|
+
console.log(` Messages inserted: ${report.messagesInserted}`);
|
|
49
|
+
console.log(` Messages updated: ${report.messagesUpdated}`);
|
|
50
|
+
console.log(` Conversations: ${report.conversationsInserted} new, ${report.conversationsUpdated} updated`);
|
|
51
|
+
console.log(` New unread: ${report.unreadDelta}`);
|
|
52
|
+
if (report.rateLimit) {
|
|
53
|
+
const wait = timeUntilNextPoll(report.rateLimit.nextPollAfter);
|
|
54
|
+
if (wait !== null && wait > 0) {
|
|
55
|
+
console.log(` Next poll allowed: in ${wait}s`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.log(' Next poll allowed: now');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.error(`✗ Sync failed: ${report.error}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
closeDatabases(coreDb, chatDb);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
sync
|
|
78
|
+
.command('status')
|
|
79
|
+
.description('Show sync status')
|
|
80
|
+
.option('--profile <name>', 'Profile to use')
|
|
81
|
+
.option('--json', 'Output in JSON format')
|
|
82
|
+
.action((opts, command) => {
|
|
83
|
+
try {
|
|
84
|
+
const profileName = resolveProfile(opts, command);
|
|
85
|
+
if (!profileName) {
|
|
86
|
+
console.error('Error: No active profile. Use "fluxra profile use <name>"');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
90
|
+
try {
|
|
91
|
+
const status = getSyncStatus(chatDb);
|
|
92
|
+
if (opts.json) {
|
|
93
|
+
output(status, { json: true });
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.log(formatSyncStatus(status));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
closeDatabases(coreDb, chatDb);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
sync
|
|
109
|
+
.command('watch')
|
|
110
|
+
.description('Start foreground watch mode')
|
|
111
|
+
.option('--profile <name>', 'Profile to use')
|
|
112
|
+
.option('--interval <sec>', 'Poll interval in seconds', '60')
|
|
113
|
+
.option('--max-runs <n>', 'Maximum number of runs')
|
|
114
|
+
.option('--backoff', 'Enable adaptive backoff')
|
|
115
|
+
.action(async (opts, command) => {
|
|
116
|
+
try {
|
|
117
|
+
const { startWatch } = await import('../../../modules/chat/sync/watch-mode.js');
|
|
118
|
+
const profileName = resolveProfile(opts, command);
|
|
119
|
+
if (!profileName) {
|
|
120
|
+
console.error('Error: No active profile');
|
|
121
|
+
process.exit(2);
|
|
122
|
+
}
|
|
123
|
+
const { coreDb } = openProfileDatabases(profileName);
|
|
124
|
+
try {
|
|
125
|
+
const maxRuns = opts.maxRuns ? parseInt(opts.maxRuns, 10) : undefined;
|
|
126
|
+
const result = await startWatch(coreDb, {
|
|
127
|
+
profileName,
|
|
128
|
+
intervalSec: parseInt(opts.interval, 10),
|
|
129
|
+
maxRuns,
|
|
130
|
+
backoff: opts.backoff,
|
|
131
|
+
});
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log('Watch Mode Stopped');
|
|
134
|
+
console.log(` Runs Completed: ${result.runsCompleted}`);
|
|
135
|
+
if (result.lastSuccess) {
|
|
136
|
+
console.log(` Last Success: ${new Date(result.lastSuccess).toLocaleString()}`);
|
|
137
|
+
}
|
|
138
|
+
if (result.lastError) {
|
|
139
|
+
console.log(` Last Error: ${result.lastError}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
closeDatabases(coreDb, coreDb);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
sync
|
|
152
|
+
.command('install-cron')
|
|
153
|
+
.description('Install cron entry for background sync')
|
|
154
|
+
.option('--profile <name>', 'Profile to use')
|
|
155
|
+
.option('--schedule <expr>', 'Cron expression (default: */5 * * * *)')
|
|
156
|
+
.action(async (opts, command) => {
|
|
157
|
+
try {
|
|
158
|
+
const { installCron } = await import('../../../modules/chat/sync/cron-manager.js');
|
|
159
|
+
const profileName = resolveProfile(opts, command);
|
|
160
|
+
if (!profileName) {
|
|
161
|
+
console.error('Error: No active profile');
|
|
162
|
+
process.exit(2);
|
|
163
|
+
}
|
|
164
|
+
const { coreDb } = openProfileDatabases(profileName);
|
|
165
|
+
try {
|
|
166
|
+
const result = await installCron(coreDb, {
|
|
167
|
+
profileName,
|
|
168
|
+
schedule: opts.schedule,
|
|
169
|
+
});
|
|
170
|
+
console.log(`✓ Cron installed for profile '${profileName}'`);
|
|
171
|
+
console.log(` Schedule: ${result.schedule}`);
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
closeDatabases(coreDb, coreDb);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
sync
|
|
183
|
+
.command('uninstall-cron')
|
|
184
|
+
.description('Uninstall cron entry for background sync')
|
|
185
|
+
.option('--profile <name>', 'Profile to use')
|
|
186
|
+
.action(async (opts, command) => {
|
|
187
|
+
try {
|
|
188
|
+
const { uninstallCron } = await import('../../../modules/chat/sync/cron-manager.js');
|
|
189
|
+
const profileName = resolveProfile(opts, command);
|
|
190
|
+
if (!profileName) {
|
|
191
|
+
console.error('Error: No active profile');
|
|
192
|
+
process.exit(2);
|
|
193
|
+
}
|
|
194
|
+
const { coreDb } = openProfileDatabases(profileName);
|
|
195
|
+
try {
|
|
196
|
+
await uninstallCron(coreDb, profileName);
|
|
197
|
+
console.log(`✓ Cron uninstalled for profile '${profileName}'`);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
closeDatabases(coreDb, coreDb);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
chat
|
|
209
|
+
.command('unread')
|
|
210
|
+
.description('Show unread messages summary')
|
|
211
|
+
.option('--profile <name>', 'Profile to use')
|
|
212
|
+
.option('--conversation <id>', 'Filter by conversation')
|
|
213
|
+
.option('--mentions', 'Show only mentions')
|
|
214
|
+
.option('--json', 'Output in JSON format')
|
|
215
|
+
.action((opts, command) => {
|
|
216
|
+
try {
|
|
217
|
+
const profileName = resolveProfile(opts, command);
|
|
218
|
+
if (!profileName) {
|
|
219
|
+
console.error('Error: No active profile');
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
223
|
+
try {
|
|
224
|
+
const summary = getUnreadSummaryData(chatDb, {
|
|
225
|
+
mentionsOnly: opts.mentions,
|
|
226
|
+
conversationId: opts.conversation,
|
|
227
|
+
});
|
|
228
|
+
if (opts.json) {
|
|
229
|
+
output(summary, { json: true });
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
console.log('Unread Summary');
|
|
233
|
+
console.log(` Total unread: ${summary.totalUnread}`);
|
|
234
|
+
console.log(` Mentions: ${summary.totalMentions}`);
|
|
235
|
+
if (summary.byConversation.length > 0) {
|
|
236
|
+
console.log('');
|
|
237
|
+
const headers = ['Conversation', 'Type', 'Unread', '@', 'Last'];
|
|
238
|
+
const rows = summary.byConversation.map(c => [
|
|
239
|
+
c.conversationName || c.conversationId.substring(0, 12),
|
|
240
|
+
c.conversationType,
|
|
241
|
+
String(c.unreadCount),
|
|
242
|
+
c.hasMention ? '✓' : '',
|
|
243
|
+
new Date(c.lastUnreadAt).toLocaleTimeString(),
|
|
244
|
+
]);
|
|
245
|
+
console.log(renderTable(headers, rows));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
closeDatabases(coreDb, chatDb);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
chat
|
|
259
|
+
.command('peek')
|
|
260
|
+
.description('Preview unread messages without marking read')
|
|
261
|
+
.option('--profile <name>', 'Profile to use')
|
|
262
|
+
.option('--conversation <id>', 'Filter by conversation')
|
|
263
|
+
.option('--mentions', 'Show only mentions')
|
|
264
|
+
.option('--limit <n>', 'Max messages to show')
|
|
265
|
+
.option('--json', 'Output in JSON format')
|
|
266
|
+
.action((opts, command) => {
|
|
267
|
+
try {
|
|
268
|
+
const profileName = resolveProfile(opts, command);
|
|
269
|
+
if (!profileName) {
|
|
270
|
+
console.error('Error: No active profile');
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
274
|
+
try {
|
|
275
|
+
const preview = getUnreadPreview(chatDb, {
|
|
276
|
+
conversationId: opts.conversation,
|
|
277
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 20,
|
|
278
|
+
mentionsOnly: opts.mentions,
|
|
279
|
+
historyBefore: 5,
|
|
280
|
+
});
|
|
281
|
+
if (opts.json) {
|
|
282
|
+
output(preview, { json: true });
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
if (preview.messages.length === 0) {
|
|
286
|
+
console.log('No unread messages.');
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
console.log(`Unread Messages (${preview.totalUnread} unread)`);
|
|
290
|
+
console.log(renderMessageList(preview.messages));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
closeDatabases(coreDb, chatDb);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
chat
|
|
304
|
+
.command('read')
|
|
305
|
+
.description('Mark unread messages as read')
|
|
306
|
+
.option('--profile <name>', 'Profile to use')
|
|
307
|
+
.option('--conversation <id>', 'Mark conversation as read')
|
|
308
|
+
.option('--mentions', 'Mark only mentions as read')
|
|
309
|
+
.option('--limit <n>', 'Max messages to mark')
|
|
310
|
+
.option('--json', 'Output in JSON format')
|
|
311
|
+
.action((opts, command) => {
|
|
312
|
+
try {
|
|
313
|
+
const profileName = resolveProfile(opts, command);
|
|
314
|
+
if (!profileName) {
|
|
315
|
+
console.error('Error: No active profile');
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
319
|
+
try {
|
|
320
|
+
const result = readMessages(chatDb, {
|
|
321
|
+
conversationId: opts.conversation,
|
|
322
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 50,
|
|
323
|
+
mentionsOnly: opts.mentions,
|
|
324
|
+
});
|
|
325
|
+
if (opts.json) {
|
|
326
|
+
output(result, { json: true });
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
console.log(`✓ Marked ${result.markedRead} message(s) as read`);
|
|
330
|
+
if (result.messages.length > 0) {
|
|
331
|
+
console.log(renderMessageList(result.messages.slice(0, 10)));
|
|
332
|
+
if (result.messages.length > 10) {
|
|
333
|
+
console.log(`... and ${result.messages.length - 10} more`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
closeDatabases(coreDb, chatDb);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
chat
|
|
348
|
+
.command('conversations')
|
|
349
|
+
.description('List conversations with unread counts')
|
|
350
|
+
.option('--profile <name>', 'Profile to use')
|
|
351
|
+
.option('--unread-only', 'Show only conversations with unread')
|
|
352
|
+
.option('--limit <n>', 'Max conversations to show')
|
|
353
|
+
.option('--json', 'Output in JSON format')
|
|
354
|
+
.action((opts, command) => {
|
|
355
|
+
try {
|
|
356
|
+
const profileName = resolveProfile(opts, command);
|
|
357
|
+
if (!profileName) {
|
|
358
|
+
console.error('Error: No active profile');
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
362
|
+
try {
|
|
363
|
+
const conversations = listConversationsWithUnread(chatDb, {
|
|
364
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 50,
|
|
365
|
+
unreadOnly: opts.unreadOnly,
|
|
366
|
+
});
|
|
367
|
+
if (opts.json) {
|
|
368
|
+
output(conversations, { json: true });
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
if (conversations.length === 0) {
|
|
372
|
+
console.log('No conversations found.');
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
const headers = ['Name', 'Type', 'Unread', 'Last Activity'];
|
|
376
|
+
const rows = conversations.map(c => [
|
|
377
|
+
c.name || c.conversationId.substring(0, 12),
|
|
378
|
+
c.type,
|
|
379
|
+
c.unreadCount > 0 ? String(c.unreadCount) : '',
|
|
380
|
+
c.lastMessageAt ? new Date(c.lastMessageAt).toLocaleString() : '',
|
|
381
|
+
]);
|
|
382
|
+
console.log(renderTable(headers, rows));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
finally {
|
|
387
|
+
closeDatabases(coreDb, chatDb);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
chat
|
|
396
|
+
.command('history')
|
|
397
|
+
.description('Browse message history of a conversation')
|
|
398
|
+
.argument('<conversation-id>', 'Conversation ID')
|
|
399
|
+
.option('--profile <name>', 'Profile to use')
|
|
400
|
+
.option('--limit <n>', 'Number of messages')
|
|
401
|
+
.option('--before <cursor>', 'Before timestamp')
|
|
402
|
+
.option('--json', 'Output in JSON format')
|
|
403
|
+
.action((convId, opts, command) => {
|
|
404
|
+
try {
|
|
405
|
+
const profileName = resolveProfile(opts, command);
|
|
406
|
+
if (!profileName) {
|
|
407
|
+
console.error('Error: No active profile');
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
411
|
+
try {
|
|
412
|
+
const history = getHistory(chatDb, convId, {
|
|
413
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 50,
|
|
414
|
+
before: opts.before,
|
|
415
|
+
});
|
|
416
|
+
if (opts.json) {
|
|
417
|
+
output(history, { json: true });
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
if (history.messages.length === 0) {
|
|
421
|
+
console.log('No messages in history.');
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
console.log(`Message History (${history.messages.length} messages)`);
|
|
425
|
+
if (history.hasMore) {
|
|
426
|
+
console.log(`(More available, use --before ${history.nextCursor})`);
|
|
427
|
+
}
|
|
428
|
+
console.log('');
|
|
429
|
+
console.log(renderMessageList(history.messages));
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
closeDatabases(coreDb, chatDb);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
chat
|
|
443
|
+
.command('search')
|
|
444
|
+
.description('Search local message cache')
|
|
445
|
+
.argument('<query>', 'Search query')
|
|
446
|
+
.option('--profile <name>', 'Profile to use')
|
|
447
|
+
.option('--conversation <id>', 'Search in specific conversation')
|
|
448
|
+
.option('--unread-only', 'Search only unread messages')
|
|
449
|
+
.option('--limit <n>', 'Max results')
|
|
450
|
+
.option('--json', 'Output in JSON format')
|
|
451
|
+
.action((query, opts, command) => {
|
|
452
|
+
try {
|
|
453
|
+
const profileName = resolveProfile(opts, command);
|
|
454
|
+
if (!profileName) {
|
|
455
|
+
console.error('Error: No active profile');
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
459
|
+
try {
|
|
460
|
+
const results = searchLocalMessages(chatDb, query, {
|
|
461
|
+
conversationId: opts.conversation,
|
|
462
|
+
unreadOnly: opts.unreadOnly,
|
|
463
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 50,
|
|
464
|
+
});
|
|
465
|
+
if (opts.json) {
|
|
466
|
+
output(results, { json: true });
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
if (results.results.length === 0) {
|
|
470
|
+
console.log(`No results for '${query}'.`);
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
console.log(`Search Results for '${query}' (${results.totalCount} found)`);
|
|
474
|
+
console.log('');
|
|
475
|
+
console.log(renderMessageList(results.results, { groupByConversation: true }));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
finally {
|
|
480
|
+
closeDatabases(coreDb, chatDb);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
485
|
+
process.exit(1);
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
chat
|
|
489
|
+
.command('send')
|
|
490
|
+
.description('Send a message')
|
|
491
|
+
.argument('<target>', 'Target conversation ID or agent ID')
|
|
492
|
+
.argument('<content>', 'Message content')
|
|
493
|
+
.option('--profile <name>', 'Profile to use')
|
|
494
|
+
.option('--reply-to <msg-id>', 'Reply to message ID')
|
|
495
|
+
.option('--mention <agent-id>', 'Mention agent (repeatable)', (val, prev) => [...prev, val], [])
|
|
496
|
+
.option('--json', 'Output in JSON format')
|
|
497
|
+
.action(async (target, content, opts, command) => {
|
|
498
|
+
try {
|
|
499
|
+
const profileName = resolveProfile(opts, command);
|
|
500
|
+
if (!profileName) {
|
|
501
|
+
console.error('Error: No active profile');
|
|
502
|
+
process.exit(1);
|
|
503
|
+
}
|
|
504
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
505
|
+
try {
|
|
506
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
507
|
+
// Auto-detect target type
|
|
508
|
+
const isAgentId = target.startsWith('agt_');
|
|
509
|
+
const sendOpts = {
|
|
510
|
+
content,
|
|
511
|
+
conversationId: isAgentId ? undefined : target,
|
|
512
|
+
recipientAgentId: isAgentId ? target : undefined,
|
|
513
|
+
inReplyTo: opts.replyTo,
|
|
514
|
+
mentions: opts.mention.length > 0 ? opts.mention : undefined,
|
|
515
|
+
};
|
|
516
|
+
const result = await sendMessage(chatDb, accessToken, sendOpts);
|
|
517
|
+
if (opts.json) {
|
|
518
|
+
output(result, { json: true });
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
console.log(`✓ Message sent`);
|
|
522
|
+
console.log(` To: ${target}`);
|
|
523
|
+
console.log(` ID: ${result.message.message_id}`);
|
|
524
|
+
if (result.outboxId) {
|
|
525
|
+
console.log(` ⚠ Queued to outbox (will retry later)`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
finally {
|
|
530
|
+
closeDatabases(coreDb, chatDb);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
chat
|
|
539
|
+
.command('edit')
|
|
540
|
+
.description('Edit a message')
|
|
541
|
+
.argument('<message-id>', 'Message ID to edit')
|
|
542
|
+
.argument('<content>', 'New content')
|
|
543
|
+
.option('--profile <name>', 'Profile to use')
|
|
544
|
+
.option('--json', 'Output in JSON format')
|
|
545
|
+
.action(async (messageId, content, opts, command) => {
|
|
546
|
+
try {
|
|
547
|
+
const profileName = resolveProfile(opts, command);
|
|
548
|
+
if (!profileName) {
|
|
549
|
+
console.error('Error: No active profile');
|
|
550
|
+
process.exit(1);
|
|
551
|
+
}
|
|
552
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
553
|
+
try {
|
|
554
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
555
|
+
const result = await editMessage(chatDb, accessToken, messageId, content);
|
|
556
|
+
if (opts.json) {
|
|
557
|
+
output(result, { json: true });
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
console.log(`✓ Message edited`);
|
|
561
|
+
console.log(` ID: ${result.messageId}`);
|
|
562
|
+
console.log(` Content: ${result.content}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
finally {
|
|
566
|
+
closeDatabases(coreDb, chatDb);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
catch (error) {
|
|
570
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
571
|
+
process.exit(1);
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
chat
|
|
575
|
+
.command('delete')
|
|
576
|
+
.description('Delete or withdraw a message')
|
|
577
|
+
.argument('<message-id>', 'Message ID')
|
|
578
|
+
.option('--profile <name>', 'Profile to use')
|
|
579
|
+
.option('--withdraw', 'Withdraw instead of delete')
|
|
580
|
+
.option('--json', 'Output in JSON format')
|
|
581
|
+
.action(async (messageId, opts, command) => {
|
|
582
|
+
try {
|
|
583
|
+
const profileName = resolveProfile(opts, command);
|
|
584
|
+
if (!profileName) {
|
|
585
|
+
console.error('Error: No active profile');
|
|
586
|
+
process.exit(1);
|
|
587
|
+
}
|
|
588
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
589
|
+
try {
|
|
590
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
591
|
+
const result = await deleteMessage(chatDb, accessToken, messageId, {
|
|
592
|
+
withdraw: opts.withdraw,
|
|
593
|
+
});
|
|
594
|
+
if (opts.json) {
|
|
595
|
+
output(result, { json: true });
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
const action = opts.withdraw ? 'withdrawn' : 'deleted';
|
|
599
|
+
console.log(`✓ Message ${action}`);
|
|
600
|
+
console.log(` ID: ${result.messageId}`);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
finally {
|
|
604
|
+
closeDatabases(coreDb, chatDb);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
609
|
+
process.exit(1);
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
// Conversation subcommands
|
|
613
|
+
const conv = chat.command('conv');
|
|
614
|
+
conv.description('Conversation management commands');
|
|
615
|
+
conv
|
|
616
|
+
.command('show')
|
|
617
|
+
.description('Show conversation detail')
|
|
618
|
+
.argument('<conversation-id>', 'Conversation ID')
|
|
619
|
+
.option('--profile <name>', 'Profile to use')
|
|
620
|
+
.option('--history <n>', 'Number of recent messages')
|
|
621
|
+
.option('--json', 'Output in JSON format')
|
|
622
|
+
.action(async (convId, opts, command) => {
|
|
623
|
+
try {
|
|
624
|
+
const profileName = resolveProfile(opts, command);
|
|
625
|
+
if (!profileName) {
|
|
626
|
+
console.error('Error: No active profile');
|
|
627
|
+
process.exit(1);
|
|
628
|
+
}
|
|
629
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
630
|
+
try {
|
|
631
|
+
const detail = getConversationDetail(chatDb, convId, {
|
|
632
|
+
historyLimit: opts.history ? parseInt(opts.history, 10) : 20,
|
|
633
|
+
});
|
|
634
|
+
if (!detail) {
|
|
635
|
+
console.error(`Error: Conversation '${convId}' not found`);
|
|
636
|
+
process.exit(1);
|
|
637
|
+
}
|
|
638
|
+
if (opts.json) {
|
|
639
|
+
output(detail, { json: true });
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
console.log(`Conversation: ${detail.conversation.name || convId}`);
|
|
643
|
+
console.log(` Type: ${detail.conversation.type}`);
|
|
644
|
+
console.log(` Created: ${new Date(detail.conversation.created_at).toLocaleString()}`);
|
|
645
|
+
console.log(` Unread: ${detail.unreadStats?.totalUnread || 0}`);
|
|
646
|
+
if (detail.unreadStats && detail.unreadStats.mentionedUnread > 0) {
|
|
647
|
+
console.log(` Mentions: ${detail.unreadStats.mentionedUnread}`);
|
|
648
|
+
}
|
|
649
|
+
if (detail.participants.length > 0) {
|
|
650
|
+
console.log('');
|
|
651
|
+
console.log('Participants:');
|
|
652
|
+
for (const p of detail.participants) {
|
|
653
|
+
console.log(` - ${p.agent_id} (${p.role})`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (detail.recentMessages.length > 0) {
|
|
657
|
+
console.log('');
|
|
658
|
+
console.log('Recent Messages:');
|
|
659
|
+
console.log(renderMessageList(detail.recentMessages));
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
finally {
|
|
664
|
+
closeDatabases(coreDb, chatDb);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
catch (error) {
|
|
668
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
669
|
+
process.exit(1);
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
conv
|
|
673
|
+
.command('create')
|
|
674
|
+
.description('Create a new conversation')
|
|
675
|
+
.option('--profile <name>', 'Profile to use')
|
|
676
|
+
.requiredOption('--type <type>', 'Conversation type (direct or group)')
|
|
677
|
+
.option('--name <name>', 'Conversation name')
|
|
678
|
+
.option('--member <agent-id>', 'Member to add (repeatable)', (val, prev) => [...prev, val], [])
|
|
679
|
+
.option('--json', 'Output in JSON format')
|
|
680
|
+
.action(async (opts, command) => {
|
|
681
|
+
try {
|
|
682
|
+
const profileName = resolveProfile(opts, command);
|
|
683
|
+
if (!profileName) {
|
|
684
|
+
console.error('Error: No active profile');
|
|
685
|
+
process.exit(1);
|
|
686
|
+
}
|
|
687
|
+
if (opts.type !== 'direct' && opts.type !== 'group') {
|
|
688
|
+
console.error('Error: Type must be "direct" or "group"');
|
|
689
|
+
process.exit(1);
|
|
690
|
+
}
|
|
691
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
692
|
+
try {
|
|
693
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
694
|
+
const result = await createConversation(chatDb, accessToken, {
|
|
695
|
+
type: opts.type,
|
|
696
|
+
name: opts.name,
|
|
697
|
+
members: opts.member.length > 0 ? opts.member : undefined,
|
|
698
|
+
});
|
|
699
|
+
if (opts.json) {
|
|
700
|
+
output(result, { json: true });
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
console.log(`✓ Conversation created`);
|
|
704
|
+
console.log(` ID: ${result.conversationId}`);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
finally {
|
|
708
|
+
closeDatabases(coreDb, chatDb);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
713
|
+
process.exit(1);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
conv
|
|
717
|
+
.command('invite')
|
|
718
|
+
.description('Invite a member to a conversation')
|
|
719
|
+
.argument('<conversation-id>', 'Conversation ID')
|
|
720
|
+
.argument('<agent-id>', 'Agent ID to invite')
|
|
721
|
+
.option('--profile <name>', 'Profile to use')
|
|
722
|
+
.option('--role <role>', 'Role (owner, admin, member)', 'member')
|
|
723
|
+
.option('--json', 'Output in JSON format')
|
|
724
|
+
.action(async (convId, agentId, opts, command) => {
|
|
725
|
+
try {
|
|
726
|
+
const profileName = resolveProfile(opts, command);
|
|
727
|
+
if (!profileName) {
|
|
728
|
+
console.error('Error: No active profile');
|
|
729
|
+
process.exit(1);
|
|
730
|
+
}
|
|
731
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
732
|
+
try {
|
|
733
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
734
|
+
const result = await inviteMember(chatDb, accessToken, convId, agentId, opts.role);
|
|
735
|
+
if (opts.json) {
|
|
736
|
+
output(result, { json: true });
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
console.log(`✓ Invited ${agentId} to conversation`);
|
|
740
|
+
console.log(` Role: ${result.role}`);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
finally {
|
|
744
|
+
closeDatabases(coreDb, chatDb);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
catch (error) {
|
|
748
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
749
|
+
process.exit(1);
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
conv
|
|
753
|
+
.command('remove')
|
|
754
|
+
.description('Remove a member from a conversation')
|
|
755
|
+
.argument('<conversation-id>', 'Conversation ID')
|
|
756
|
+
.argument('<agent-id>', 'Agent ID to remove')
|
|
757
|
+
.option('--profile <name>', 'Profile to use')
|
|
758
|
+
.option('--json', 'Output in JSON format')
|
|
759
|
+
.action(async (convId, agentId, opts, command) => {
|
|
760
|
+
try {
|
|
761
|
+
const profileName = resolveProfile(opts, command);
|
|
762
|
+
if (!profileName) {
|
|
763
|
+
console.error('Error: No active profile');
|
|
764
|
+
process.exit(1);
|
|
765
|
+
}
|
|
766
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
767
|
+
try {
|
|
768
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
769
|
+
await removeMember(chatDb, accessToken, convId, agentId);
|
|
770
|
+
if (opts.json) {
|
|
771
|
+
output({ success: true, agentId }, { json: true });
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
console.log(`✓ Removed ${agentId} from conversation`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
finally {
|
|
778
|
+
closeDatabases(coreDb, chatDb);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
catch (error) {
|
|
782
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
783
|
+
process.exit(1);
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
conv
|
|
787
|
+
.command('role')
|
|
788
|
+
.description('Update a member role')
|
|
789
|
+
.argument('<conversation-id>', 'Conversation ID')
|
|
790
|
+
.argument('<agent-id>', 'Agent ID')
|
|
791
|
+
.argument('<role>', 'New role (owner, admin, member)')
|
|
792
|
+
.option('--profile <name>', 'Profile to use')
|
|
793
|
+
.option('--json', 'Output in JSON format')
|
|
794
|
+
.action(async (convId, agentId, role, opts, command) => {
|
|
795
|
+
try {
|
|
796
|
+
const profileName = resolveProfile(opts, command);
|
|
797
|
+
if (!profileName) {
|
|
798
|
+
console.error('Error: No active profile');
|
|
799
|
+
process.exit(1);
|
|
800
|
+
}
|
|
801
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
802
|
+
try {
|
|
803
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
804
|
+
const result = await updateRole(chatDb, accessToken, convId, agentId, role);
|
|
805
|
+
if (opts.json) {
|
|
806
|
+
output(result, { json: true });
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
console.log(`✓ Updated ${agentId} role to ${role}`);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
finally {
|
|
813
|
+
closeDatabases(coreDb, chatDb);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
catch (error) {
|
|
817
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
818
|
+
process.exit(1);
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
conv
|
|
822
|
+
.command('leave')
|
|
823
|
+
.description('Leave a conversation')
|
|
824
|
+
.argument('<conversation-id>', 'Conversation ID')
|
|
825
|
+
.option('--profile <name>', 'Profile to use')
|
|
826
|
+
.option('--json', 'Output in JSON format')
|
|
827
|
+
.action(async (convId, opts, command) => {
|
|
828
|
+
try {
|
|
829
|
+
const profileName = resolveProfile(opts, command);
|
|
830
|
+
if (!profileName) {
|
|
831
|
+
console.error('Error: No active profile');
|
|
832
|
+
process.exit(1);
|
|
833
|
+
}
|
|
834
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
835
|
+
try {
|
|
836
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
837
|
+
await leaveConversation(chatDb, accessToken, convId);
|
|
838
|
+
if (opts.json) {
|
|
839
|
+
output({ success: true, conversationId: convId }, { json: true });
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
console.log(`✓ Left conversation ${convId}`);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
finally {
|
|
846
|
+
closeDatabases(coreDb, chatDb);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
catch (error) {
|
|
850
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
851
|
+
process.exit(1);
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
// Block commands
|
|
855
|
+
chat
|
|
856
|
+
.command('block')
|
|
857
|
+
.description('Block an agent or conversation')
|
|
858
|
+
.argument('<target-id>', 'Target ID to block')
|
|
859
|
+
.option('--profile <name>', 'Profile to use')
|
|
860
|
+
.option('--type <type>', 'Block type (agent or group)', 'agent')
|
|
861
|
+
.option('--json', 'Output in JSON format')
|
|
862
|
+
.action(async (targetId, opts, command) => {
|
|
863
|
+
try {
|
|
864
|
+
const { createBlock } = await import('../../../core/http/block-api.js');
|
|
865
|
+
const profileName = resolveProfile(opts, command);
|
|
866
|
+
if (!profileName) {
|
|
867
|
+
console.error('Error: No active profile');
|
|
868
|
+
process.exit(1);
|
|
869
|
+
}
|
|
870
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
871
|
+
const block = await createBlock(accessToken, {
|
|
872
|
+
type: opts.type,
|
|
873
|
+
target_id: targetId,
|
|
874
|
+
});
|
|
875
|
+
if (opts.json) {
|
|
876
|
+
output(block, { json: true });
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
console.log(`✓ Blocked ${targetId}`);
|
|
880
|
+
console.log(` Block ID: ${block.block_id}`);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
catch (error) {
|
|
884
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
885
|
+
process.exit(1);
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
chat
|
|
889
|
+
.command('unblock')
|
|
890
|
+
.description('Unblock an agent or conversation')
|
|
891
|
+
.argument('<block-id>', 'Block ID to remove')
|
|
892
|
+
.option('--profile <name>', 'Profile to use')
|
|
893
|
+
.option('--json', 'Output in JSON format')
|
|
894
|
+
.action(async (blockId, opts, command) => {
|
|
895
|
+
try {
|
|
896
|
+
const { removeBlock } = await import('../../../core/http/block-api.js');
|
|
897
|
+
const profileName = resolveProfile(opts, command);
|
|
898
|
+
if (!profileName) {
|
|
899
|
+
console.error('Error: No active profile');
|
|
900
|
+
process.exit(1);
|
|
901
|
+
}
|
|
902
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
903
|
+
await removeBlock(accessToken, blockId);
|
|
904
|
+
if (opts.json) {
|
|
905
|
+
output({ success: true, blockId }, { json: true });
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
console.log(`✓ Unblocked ${blockId}`);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
catch (error) {
|
|
912
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
913
|
+
process.exit(1);
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
chat
|
|
917
|
+
.command('blocks')
|
|
918
|
+
.description('List all blocks')
|
|
919
|
+
.option('--profile <name>', 'Profile to use')
|
|
920
|
+
.option('--json', 'Output in JSON format')
|
|
921
|
+
.action(async (opts, command) => {
|
|
922
|
+
try {
|
|
923
|
+
const { listBlocks } = await import('../../../core/http/block-api.js');
|
|
924
|
+
const profileName = resolveProfile(opts, command);
|
|
925
|
+
if (!profileName) {
|
|
926
|
+
console.error('Error: No active profile');
|
|
927
|
+
process.exit(1);
|
|
928
|
+
}
|
|
929
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
930
|
+
const blocks = await listBlocks(accessToken);
|
|
931
|
+
if (opts.json) {
|
|
932
|
+
output(blocks, { json: true });
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
if (blocks.blocks.length === 0) {
|
|
936
|
+
console.log('No blocks.');
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
const headers = ['Block ID', 'Type', 'Target ID', 'Created'];
|
|
940
|
+
const rows = blocks.blocks.map(b => [
|
|
941
|
+
b.block_id || "<unknown>",
|
|
942
|
+
b.type || "<unknown>",
|
|
943
|
+
b.target_id || "<unknown>",
|
|
944
|
+
b.created_at ? new Date(b.created_at).toLocaleString() : "<unknown>",
|
|
945
|
+
]);
|
|
946
|
+
console.log(renderTable(headers, rows));
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
catch (error) {
|
|
951
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
952
|
+
process.exit(1);
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
// Directory commands
|
|
956
|
+
const directory = chat.command('directory');
|
|
957
|
+
directory.description('Agent directory commands');
|
|
958
|
+
const dirSearch = directory.command('search');
|
|
959
|
+
dirSearch.description('Search agent directory');
|
|
960
|
+
dirSearch
|
|
961
|
+
.argument('<query>', 'Search query')
|
|
962
|
+
.description('Search for agents')
|
|
963
|
+
.option('--profile <name>', 'Profile to use')
|
|
964
|
+
.option('--limit <n>', 'Max results')
|
|
965
|
+
.option('--json', 'Output in JSON format')
|
|
966
|
+
.action(async (query, opts, command) => {
|
|
967
|
+
try {
|
|
968
|
+
const { searchDirectory } = await import('../../../core/http/directory-api.js');
|
|
969
|
+
const { cacheSearchResults } = await import('../../../modules/chat/send/directory-cache-service.js');
|
|
970
|
+
const profileName = resolveProfile(opts, command);
|
|
971
|
+
if (!profileName) {
|
|
972
|
+
console.error('Error: No active profile');
|
|
973
|
+
process.exit(1);
|
|
974
|
+
}
|
|
975
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
976
|
+
try {
|
|
977
|
+
const results = await searchDirectory(query, {
|
|
978
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 20,
|
|
979
|
+
});
|
|
980
|
+
// Cache results
|
|
981
|
+
cacheSearchResults(chatDb, results.profiles);
|
|
982
|
+
if (opts.json) {
|
|
983
|
+
output(results, { json: true });
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
if (results.profiles.length === 0) {
|
|
987
|
+
console.log(`No results for '${query}'.`);
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
console.log(`Search Results for '${query}' (${results.profiles.length} found)`);
|
|
991
|
+
const headers = ['Agent ID', 'Name', 'Category', 'Status'];
|
|
992
|
+
const rows = results.profiles.map(a => [
|
|
993
|
+
a.agent_id,
|
|
994
|
+
a.display_name || '<unnamed>',
|
|
995
|
+
a.category || '<none>',
|
|
996
|
+
a.status || '<none>',
|
|
997
|
+
]);
|
|
998
|
+
console.log(renderTable(headers, rows));
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
finally {
|
|
1003
|
+
closeDatabases(coreDb, chatDb);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
catch (error) {
|
|
1007
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1008
|
+
process.exit(1);
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
directory
|
|
1012
|
+
.command('random')
|
|
1013
|
+
.description('Get random agent recommendations')
|
|
1014
|
+
.option('--profile <name>', 'Profile to use')
|
|
1015
|
+
.option('--limit <n>', 'Number of recommendations')
|
|
1016
|
+
.option('--json', 'Output in JSON format')
|
|
1017
|
+
.action(async (opts, command) => {
|
|
1018
|
+
try {
|
|
1019
|
+
const { getRandomRecommendations } = await import('../../../core/http/directory-api.js');
|
|
1020
|
+
const { cacheSearchResults } = await import('../../../modules/chat/send/directory-cache-service.js');
|
|
1021
|
+
const profileName = resolveProfile(opts, command);
|
|
1022
|
+
if (!profileName) {
|
|
1023
|
+
console.error('Error: No active profile');
|
|
1024
|
+
process.exit(1);
|
|
1025
|
+
}
|
|
1026
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
1027
|
+
try {
|
|
1028
|
+
const agents = await getRandomRecommendations(opts.limit ? parseInt(opts.limit, 10) : 10);
|
|
1029
|
+
// Cache results
|
|
1030
|
+
cacheSearchResults(chatDb, agents);
|
|
1031
|
+
if (opts.json) {
|
|
1032
|
+
output(agents, { json: true });
|
|
1033
|
+
}
|
|
1034
|
+
else {
|
|
1035
|
+
if (agents.length === 0) {
|
|
1036
|
+
console.log('No recommendations available.');
|
|
1037
|
+
}
|
|
1038
|
+
else {
|
|
1039
|
+
console.log('Random Recommendations:');
|
|
1040
|
+
const headers = ['Agent ID', 'Name', 'Category', 'Status'];
|
|
1041
|
+
const rows = agents.map(a => [
|
|
1042
|
+
a.agent_id,
|
|
1043
|
+
a.display_name || '<unnamed>',
|
|
1044
|
+
a.category || '<none>',
|
|
1045
|
+
a.status || '<none>',
|
|
1046
|
+
]);
|
|
1047
|
+
console.log(renderTable(headers, rows));
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
finally {
|
|
1052
|
+
closeDatabases(coreDb, chatDb);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
catch (error) {
|
|
1056
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1057
|
+
process.exit(1);
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
const profile = directory.command('profile');
|
|
1061
|
+
profile.description('Directory profile management');
|
|
1062
|
+
profile
|
|
1063
|
+
.command('get')
|
|
1064
|
+
.description('Get agent profile')
|
|
1065
|
+
.argument('<agent-id>', 'Agent ID')
|
|
1066
|
+
.option('--profile <name>', 'Profile to use')
|
|
1067
|
+
.option('--json', 'Output in JSON format')
|
|
1068
|
+
.action(async (agentId, opts, command) => {
|
|
1069
|
+
try {
|
|
1070
|
+
const { getAgentProfile: getApi } = await import('../../../core/http/directory-api.js');
|
|
1071
|
+
const { getAgentProfile: getCached } = await import('../../../modules/chat/store/directory-cache-repo.js');
|
|
1072
|
+
const { cacheProfile } = await import('../../../modules/chat/send/directory-cache-service.js');
|
|
1073
|
+
const profileName = resolveProfile(opts, command);
|
|
1074
|
+
if (!profileName) {
|
|
1075
|
+
console.error('Error: No active profile');
|
|
1076
|
+
process.exit(1);
|
|
1077
|
+
}
|
|
1078
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
1079
|
+
try {
|
|
1080
|
+
// Check cache first
|
|
1081
|
+
let cachedProfile = getCached(chatDb, agentId);
|
|
1082
|
+
if (!cachedProfile) {
|
|
1083
|
+
// Fetch from API
|
|
1084
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
1085
|
+
const apiProfile = await getApi(agentId, accessToken);
|
|
1086
|
+
cacheProfile(chatDb, {
|
|
1087
|
+
agent_id: apiProfile.agent_id,
|
|
1088
|
+
display_name: apiProfile.display_name,
|
|
1089
|
+
introduction: apiProfile.introduction,
|
|
1090
|
+
category: apiProfile.category,
|
|
1091
|
+
status: apiProfile.status,
|
|
1092
|
+
});
|
|
1093
|
+
cachedProfile = {
|
|
1094
|
+
agent_id: apiProfile.agent_id,
|
|
1095
|
+
display_name: apiProfile.display_name || null,
|
|
1096
|
+
introduction: apiProfile.introduction || null,
|
|
1097
|
+
category: apiProfile.category || null,
|
|
1098
|
+
status: apiProfile.status || null,
|
|
1099
|
+
cached_at: new Date().toISOString(),
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
if (opts.json) {
|
|
1103
|
+
output(cachedProfile, { json: true });
|
|
1104
|
+
}
|
|
1105
|
+
else {
|
|
1106
|
+
console.log(`Agent Profile: ${agentId}`);
|
|
1107
|
+
console.log(` Name: ${cachedProfile.display_name || '<unnamed>'}`);
|
|
1108
|
+
console.log(` Category: ${cachedProfile.category || '<none>'}`);
|
|
1109
|
+
console.log(` Introduction: ${cachedProfile.introduction || '<none>'}`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
finally {
|
|
1113
|
+
closeDatabases(coreDb, chatDb);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
catch (error) {
|
|
1117
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1118
|
+
process.exit(1);
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
profile
|
|
1122
|
+
.command('set')
|
|
1123
|
+
.description('Create or update your profile')
|
|
1124
|
+
.option('--profile <name>', 'Profile to use')
|
|
1125
|
+
.option('--intro <text>', 'Introduction text')
|
|
1126
|
+
.option('--category <cat>', 'Category')
|
|
1127
|
+
.option('--status <status>', 'Status (active, inactive, busy)')
|
|
1128
|
+
.option('--json', 'Output in JSON format')
|
|
1129
|
+
.action(async (opts, command) => {
|
|
1130
|
+
try {
|
|
1131
|
+
const { upsertProfile: upsertApi } = await import('../../../core/http/directory-profile-api.js');
|
|
1132
|
+
const { cacheProfile } = await import('../../../modules/chat/send/directory-cache-service.js');
|
|
1133
|
+
const profileName = resolveProfile(opts, command);
|
|
1134
|
+
if (!profileName) {
|
|
1135
|
+
console.error('Error: No active profile');
|
|
1136
|
+
process.exit(1);
|
|
1137
|
+
}
|
|
1138
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
1139
|
+
const apiProfile = await upsertApi(accessToken, {
|
|
1140
|
+
introduction: opts.intro,
|
|
1141
|
+
category: opts.category,
|
|
1142
|
+
status: opts.status,
|
|
1143
|
+
});
|
|
1144
|
+
// Cache the profile
|
|
1145
|
+
const { coreDb, chatDb } = openProfileDatabases(profileName);
|
|
1146
|
+
try {
|
|
1147
|
+
cacheProfile(chatDb, {
|
|
1148
|
+
agent_id: apiProfile.agent_id,
|
|
1149
|
+
display_name: apiProfile.agent_id,
|
|
1150
|
+
introduction: apiProfile.introduction,
|
|
1151
|
+
category: apiProfile.category,
|
|
1152
|
+
status: apiProfile.status,
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
finally {
|
|
1156
|
+
closeDatabases(coreDb, chatDb);
|
|
1157
|
+
}
|
|
1158
|
+
if (opts.json) {
|
|
1159
|
+
output(apiProfile, { json: true });
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
console.log('✓ Profile updated');
|
|
1163
|
+
console.log(` Agent ID: ${apiProfile.agent_id}`);
|
|
1164
|
+
console.log(` Category: ${apiProfile.category || '<none>'}`);
|
|
1165
|
+
console.log(` Status: ${apiProfile.status || '<none>'}`);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
catch (error) {
|
|
1169
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1170
|
+
process.exit(1);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
profile
|
|
1174
|
+
.command('delete')
|
|
1175
|
+
.description('Delete your profile')
|
|
1176
|
+
.option('--profile <name>', 'Profile to use')
|
|
1177
|
+
.option('--json', 'Output in JSON format')
|
|
1178
|
+
.action(async (opts, command) => {
|
|
1179
|
+
try {
|
|
1180
|
+
const { deleteProfile: deleteApi } = await import('../../../core/http/directory-profile-api.js');
|
|
1181
|
+
const profileName = resolveProfile(opts, command);
|
|
1182
|
+
if (!profileName) {
|
|
1183
|
+
console.error('Error: No active profile');
|
|
1184
|
+
process.exit(1);
|
|
1185
|
+
}
|
|
1186
|
+
const accessToken = await ensureValidAccessToken(profileName);
|
|
1187
|
+
await deleteApi(accessToken);
|
|
1188
|
+
if (opts.json) {
|
|
1189
|
+
output({ success: true }, { json: true });
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
console.log('✓ Profile deleted');
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
catch (error) {
|
|
1196
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1197
|
+
process.exit(1);
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
//# sourceMappingURL=index.js.map
|