twinclaw 1.1.6 → 1.1.8
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/dist/core/cli.js
CHANGED
|
@@ -166,10 +166,13 @@ export const handleVersionCli = async (argv) => {
|
|
|
166
166
|
* Handle the `start` command.
|
|
167
167
|
* Starts the gateway.
|
|
168
168
|
*/
|
|
169
|
-
export const handleStartCli = async (argv) => {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
export const handleStartCli = async (argv, isChatMode = false) => {
|
|
170
|
+
// We return 0 to tell main() to continue with the startup flow
|
|
171
|
+
// If we wanted to start JUST the gateway and exit, we'd do something else
|
|
172
|
+
// But here, 'start' means 'run the app'.
|
|
173
|
+
if (isChatMode) {
|
|
174
|
+
global.TWINCLAW_CHAT_MODE = true;
|
|
175
|
+
}
|
|
173
176
|
return 0;
|
|
174
177
|
};
|
|
175
178
|
/**
|
|
@@ -239,6 +242,7 @@ export function handleUnknownCommand(argv) {
|
|
|
239
242
|
'version',
|
|
240
243
|
'start',
|
|
241
244
|
'stop',
|
|
245
|
+
'chat',
|
|
242
246
|
'help'
|
|
243
247
|
]);
|
|
244
248
|
if (KNOWN_COMMANDS.has(command) || command.startsWith('--') || command.startsWith('-')) {
|
package/dist/core/onboarding.js
CHANGED
|
@@ -33,29 +33,19 @@ export function startBasicREPL(gateway) {
|
|
|
33
33
|
}
|
|
34
34
|
const WIZARD_SECTIONS = [
|
|
35
35
|
{
|
|
36
|
-
id: '
|
|
37
|
-
label: '
|
|
38
|
-
fields: [
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
id: 'models',
|
|
42
|
-
label: 'Intelligence & Models',
|
|
43
|
-
fields: ['OPENROUTER_API_KEY', 'MODAL_API_KEY', 'GEMINI_API_KEY', 'GROQ_API_KEY', 'GITHUB_TOKEN'],
|
|
36
|
+
id: 'channel',
|
|
37
|
+
label: 'STEP 1: Choose Your Messaging Channel',
|
|
38
|
+
fields: [], // Special handling for channel selection
|
|
44
39
|
},
|
|
45
40
|
{
|
|
46
|
-
id: '
|
|
47
|
-
label: '
|
|
48
|
-
fields: ['
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: 'messaging',
|
|
52
|
-
label: 'Messaging & Channels',
|
|
53
|
-
fields: ['TELEGRAM_BOT_TOKEN', 'TELEGRAM_USER_ID', 'WHATSAPP_PHONE_NUMBER'],
|
|
41
|
+
id: 'security',
|
|
42
|
+
label: 'STEP 2: Security',
|
|
43
|
+
fields: ['API_SECRET', 'API_PORT'],
|
|
54
44
|
},
|
|
55
45
|
{
|
|
56
|
-
id: '
|
|
57
|
-
label: '
|
|
58
|
-
fields: ['
|
|
46
|
+
id: 'models',
|
|
47
|
+
label: 'STEP 3: AI Models',
|
|
48
|
+
fields: ['OPENROUTER_API_KEY', 'MODAL_API_KEY', 'GEMINI_API_KEY', 'GROQ_API_KEY'],
|
|
59
49
|
},
|
|
60
50
|
];
|
|
61
51
|
const EMBEDDING_PROVIDERS = new Set(['openai', 'ollama']);
|
|
@@ -719,100 +709,99 @@ async function promptFieldValue(field, currentValue, prompter, logger) {
|
|
|
719
709
|
}
|
|
720
710
|
async function collectInteractiveUpdates(existing, logger, prompter) {
|
|
721
711
|
const workspaceDir = getWorkspaceDir();
|
|
722
|
-
logger.log('\
|
|
723
|
-
logger.log('
|
|
724
|
-
logger.log(
|
|
725
|
-
logger.log(
|
|
726
|
-
logger.log("Secret prompts are masked. Type '-' to clear an existing optional value.\n");
|
|
712
|
+
logger.log('\n═══════════════════════════════════════════════════════════');
|
|
713
|
+
logger.log(' 🎉 Welcome to TwinClaw Setup!');
|
|
714
|
+
logger.log('═══════════════════════════════════════════════════════════');
|
|
715
|
+
logger.log(`\n📁 Workspace: ${workspaceDir}`);
|
|
727
716
|
const updates = {};
|
|
728
717
|
let candidate = cloneConfig(existing);
|
|
729
718
|
for (const section of WIZARD_SECTIONS) {
|
|
730
|
-
|
|
731
|
-
|
|
719
|
+
logger.log('\n═══════════════════════════════════════════════════════════');
|
|
720
|
+
logger.log(` ${section.label}`);
|
|
721
|
+
logger.log('═══════════════════════════════════════════════════════════\n');
|
|
722
|
+
if (section.id === 'channel') {
|
|
723
|
+
logger.log('How would you like to connect with TwinClaw?');
|
|
732
724
|
logger.log('──────────────────────────────────────────────────');
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
725
|
+
logger.log(' 1. Terminal Only (Chat directly in terminal)');
|
|
726
|
+
logger.log(' 2. Telegram');
|
|
727
|
+
logger.log(' 3. WhatsApp');
|
|
728
|
+
logger.log(' 4. Both Telegram & WhatsApp');
|
|
729
|
+
const choice = await prompter.prompt('\nEnter number: ');
|
|
730
|
+
if (choice === '2' || choice === '4') {
|
|
731
|
+
const token = await promptFieldValue(ONBOARD_FIELDS.find(f => f.key === 'TELEGRAM_BOT_TOKEN'), '', prompter, logger);
|
|
732
|
+
if (token) {
|
|
733
|
+
updates['TELEGRAM_BOT_TOKEN'] = token;
|
|
734
|
+
candidate = applyUpdates(candidate, { 'TELEGRAM_BOT_TOKEN': token });
|
|
735
|
+
const userId = await promptFieldValue(ONBOARD_FIELDS.find(f => f.key === 'TELEGRAM_USER_ID'), '', prompter, logger);
|
|
736
|
+
if (userId) {
|
|
737
|
+
updates['TELEGRAM_USER_ID'] = userId;
|
|
738
|
+
candidate = applyUpdates(candidate, { 'TELEGRAM_USER_ID': userId });
|
|
739
|
+
}
|
|
737
740
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
741
|
+
}
|
|
742
|
+
if (choice === '3' || choice === '4') {
|
|
743
|
+
const phone = await promptFieldValue(ONBOARD_FIELDS.find(f => f.key === 'WHATSAPP_PHONE_NUMBER'), '', prompter, logger);
|
|
744
|
+
if (phone) {
|
|
745
|
+
updates['WHATSAPP_PHONE_NUMBER'] = phone;
|
|
746
|
+
candidate = applyUpdates(candidate, { 'WHATSAPP_PHONE_NUMBER': phone });
|
|
743
747
|
}
|
|
744
748
|
}
|
|
745
|
-
|
|
746
|
-
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
if (section.id === 'models') {
|
|
752
|
+
logger.log('You need at least one AI model API key.');
|
|
753
|
+
logger.log('Free keys available at:');
|
|
754
|
+
logger.log(' - OpenRouter: https://openrouter.ai/keys');
|
|
755
|
+
logger.log(' - Google AI: https://aistudio.google.com/app/apikey');
|
|
756
|
+
logger.log(' - Modal: https://modal.com');
|
|
757
|
+
}
|
|
758
|
+
for (const fieldKey of section.fields) {
|
|
759
|
+
const field = ONBOARD_FIELDS.find((item) => item.key === fieldKey);
|
|
760
|
+
if (!field) {
|
|
747
761
|
continue;
|
|
748
762
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
763
|
+
const current = readOnboardConfigValue(candidate, field.key);
|
|
764
|
+
const nextValue = await promptFieldValue(field, current, prompter, logger);
|
|
765
|
+
if (nextValue !== undefined) {
|
|
766
|
+
updates[field.key] = nextValue;
|
|
767
|
+
candidate = applyUpdates(candidate, { [field.key]: nextValue });
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (section.id === 'models' && !hasAnyModelKey(candidate)) {
|
|
771
|
+
logger.warn('\nAt least one model API key is required (OpenRouter, Modal, Gemini).');
|
|
772
|
+
// Force retry this section
|
|
773
|
+
// In a real loop we'd handle this better, but for simplicity here:
|
|
774
|
+
const orKey = await promptFieldValue(ONBOARD_FIELDS.find(f => f.key === 'OPENROUTER_API_KEY'), '', prompter, logger);
|
|
775
|
+
if (orKey) {
|
|
776
|
+
updates['OPENROUTER_API_KEY'] = orKey;
|
|
777
|
+
candidate = applyUpdates(candidate, { 'OPENROUTER_API_KEY': orKey });
|
|
760
778
|
}
|
|
761
|
-
break;
|
|
762
779
|
}
|
|
763
780
|
}
|
|
764
781
|
while (true) {
|
|
782
|
+
logger.log('\n═══════════════════════════════════════════════════════════');
|
|
783
|
+
logger.log(' ✅ Setup Complete!');
|
|
784
|
+
logger.log('═══════════════════════════════════════════════════════════');
|
|
765
785
|
logger.log('\nSummary of Configuration:');
|
|
766
786
|
logger.log('──────────────────────────────────────────────────');
|
|
767
787
|
for (const field of ONBOARD_FIELDS) {
|
|
768
788
|
const val = readOnboardConfigValue(candidate, field.key);
|
|
769
|
-
|
|
770
|
-
? val
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
: val || '(not set)';
|
|
774
|
-
logger.log(` ${field.label}: ${displayVal}`);
|
|
789
|
+
if (val || field.required) {
|
|
790
|
+
const displayVal = (field.secret || SECRET_KEYS.has(field.key)) ? (val ? '********' : '(not set)') : (val || '(not set)');
|
|
791
|
+
logger.log(` ${field.label}: ${displayVal}`);
|
|
792
|
+
}
|
|
775
793
|
}
|
|
776
794
|
const choice = await prompter.prompt('\nConfirm configuration? [y]es, [n]o (cancel), [e]dit: ');
|
|
777
795
|
const lower = choice.toLowerCase();
|
|
778
796
|
if (lower === 'y' || lower === 'yes') {
|
|
779
|
-
if (!hasAnyModelKey(candidate)) {
|
|
780
|
-
logger.warn('\nAt least one model API key is required (OpenRouter, Modal, Gemini, or GitHub Copilot).');
|
|
781
|
-
continue;
|
|
782
|
-
}
|
|
783
797
|
return updates;
|
|
784
798
|
}
|
|
785
799
|
if (lower === 'n' || lower === 'no') {
|
|
786
800
|
throw new OnboardingCancelledError();
|
|
787
801
|
}
|
|
788
802
|
if (lower === 'e' || lower === 'edit') {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
logger.log(` ${i + 1}. ${s.label}`);
|
|
792
|
-
});
|
|
793
|
-
const sectionIdxStr = await prompter.prompt('\nSection number: ');
|
|
794
|
-
const sectionIdx = Number.parseInt(sectionIdxStr, 10) - 1;
|
|
795
|
-
if (WIZARD_SECTIONS[sectionIdx]) {
|
|
796
|
-
const section = WIZARD_SECTIONS[sectionIdx];
|
|
797
|
-
logger.log(`\nEditing Section: ${section.label}`);
|
|
798
|
-
logger.log('──────────────────────────────────────────────────');
|
|
799
|
-
for (const fieldKey of section.fields) {
|
|
800
|
-
const field = ONBOARD_FIELDS.find((item) => item.key === fieldKey);
|
|
801
|
-
if (!field) {
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
const current = readOnboardConfigValue(candidate, field.key);
|
|
805
|
-
const nextValue = await promptFieldValue(field, current, prompter, logger);
|
|
806
|
-
if (nextValue !== undefined) {
|
|
807
|
-
updates[field.key] = nextValue;
|
|
808
|
-
candidate = applyUpdates(candidate, { [field.key]: nextValue });
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
logger.warn('Invalid section number.');
|
|
814
|
-
}
|
|
815
|
-
continue;
|
|
803
|
+
// Simple re-run for now to keep it clean
|
|
804
|
+
return collectInteractiveUpdates(existing, logger, prompter);
|
|
816
805
|
}
|
|
817
806
|
logger.warn("Please enter 'y', 'n', or 'e'.");
|
|
818
807
|
}
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,7 @@ const CLI_HANDLERS = [
|
|
|
67
67
|
{ command: ['version', '--version', '-v'], handler: handleVersionCli, priority: CLI_HANDLER_PRIORITY.VERSION, description: 'Show version' },
|
|
68
68
|
{ command: 'start', handler: handleStartCli, priority: CLI_HANDLER_PRIORITY.START_STOP, description: 'Start gateway' },
|
|
69
69
|
{ command: 'stop', handler: handleStopCli, priority: CLI_HANDLER_PRIORITY.START_STOP, description: 'Stop gateway' },
|
|
70
|
+
{ command: 'chat', handler: async (args) => { return await handleStartCli(['start', ...args.slice(1)], true); }, priority: CLI_HANDLER_PRIORITY.START_STOP, description: 'Open terminal chat' },
|
|
70
71
|
{ command: 'secret', handler: handleSecretCommandCli, priority: CLI_HANDLER_PRIORITY.CONFIG, description: 'Manage secrets' },
|
|
71
72
|
{ command: 'config', handler: handleConfigCommandCli, priority: CLI_HANDLER_PRIORITY.CONFIG, description: 'Validate runtime config' },
|
|
72
73
|
{ command: 'pairing', handler: async (args) => { return await handlePairingCli(args, pairingService) ? 0 : 1; }, priority: CLI_HANDLER_PRIORITY.CONFIG, description: 'Manage pairings' },
|
|
@@ -122,7 +123,6 @@ async function tryAutoSetup() {
|
|
|
122
123
|
printPreStartValidationFailure(postSetupValidation.blockingIssues);
|
|
123
124
|
return false;
|
|
124
125
|
}
|
|
125
|
-
console.log("\n[TwinClaw] Setup complete. Initializing Gateway...\n");
|
|
126
126
|
return true;
|
|
127
127
|
}
|
|
128
128
|
async function main() {
|
|
@@ -137,11 +137,19 @@ async function main() {
|
|
|
137
137
|
}
|
|
138
138
|
// Sort handlers by priority
|
|
139
139
|
const sortedHandlers = [...CLI_HANDLERS].sort((a, b) => b.priority - a.priority);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
140
|
+
if (command) {
|
|
141
|
+
let commandHandled = false;
|
|
142
|
+
for (const def of sortedHandlers) {
|
|
143
|
+
const commands = Array.isArray(def.command) ? def.command : [def.command];
|
|
144
|
+
if (commands.includes(command)) {
|
|
145
|
+
commandHandled = true;
|
|
146
|
+
const exitCode = await def.handler(argv);
|
|
147
|
+
process.exit(exitCode);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!commandHandled && !command.startsWith('-')) {
|
|
151
|
+
handleUnknownCommand(argv);
|
|
152
|
+
process.exit(1);
|
|
145
153
|
}
|
|
146
154
|
}
|
|
147
155
|
// Handle help flags early if no command matched
|
|
@@ -149,9 +157,6 @@ async function main() {
|
|
|
149
157
|
await handleHelpCli(argv);
|
|
150
158
|
process.exit(0);
|
|
151
159
|
}
|
|
152
|
-
if (command && handleUnknownCommand(argv)) {
|
|
153
|
-
process.exit(1);
|
|
154
|
-
}
|
|
155
160
|
checkAndMigrateWorkspace();
|
|
156
161
|
// If no command provided, try to start the gateway
|
|
157
162
|
if (!(await tryAutoSetup())) {
|
|
@@ -248,6 +253,9 @@ async function main() {
|
|
|
248
253
|
deny: parseToolSelectors(getConfigValue('TOOLS_DENY')),
|
|
249
254
|
},
|
|
250
255
|
});
|
|
256
|
+
if (global.TWINCLAW_CHAT_MODE) {
|
|
257
|
+
startBasicREPL(gateway);
|
|
258
|
+
}
|
|
251
259
|
const telegramBotToken = secretVault.readSecret('TELEGRAM_BOT_TOKEN') ?? getConfigValue('TELEGRAM_BOT_TOKEN');
|
|
252
260
|
const twinClawConfig = await readConfig();
|
|
253
261
|
const telegramUserIdRaw = getConfigValue('TELEGRAM_USER_ID');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getSecretVaultService } from './secret-vault.js';
|
|
2
2
|
import { getConfigValue } from '../config/json-config.js';
|
|
3
|
+
import { logThoughtThrottled } from '../utils/logger.js';
|
|
3
4
|
const DEFAULT_OPENAI_URL = 'https://api.openai.com/v1/embeddings';
|
|
4
5
|
const DEFAULT_OPENAI_MODEL = 'text-embedding-3-small';
|
|
5
6
|
const DEFAULT_OLLAMA_URL = 'http://localhost:11434';
|
|
@@ -81,12 +82,14 @@ export class EmbeddingService {
|
|
|
81
82
|
}
|
|
82
83
|
return null;
|
|
83
84
|
}
|
|
84
|
-
debugLog(message) {
|
|
85
|
+
async debugLog(message) {
|
|
85
86
|
const debugFlag = process.env.DEBUG?.trim().toLowerCase();
|
|
86
87
|
const debugEnabled = Boolean(debugFlag && debugFlag !== '0' && debugFlag !== 'false');
|
|
87
88
|
if (debugEnabled) {
|
|
88
89
|
console.warn(message);
|
|
89
90
|
}
|
|
91
|
+
// Always log to thought log, but throttled to prevent spam
|
|
92
|
+
await logThoughtThrottled('embedding_error', message, 30000); // 30s throttle
|
|
90
93
|
}
|
|
91
94
|
getProviderOrder() {
|
|
92
95
|
const configured = (getConfigValue('EMBEDDING_PROVIDER') ?? '').toLowerCase().trim();
|
|
@@ -91,8 +91,9 @@ export class ProactiveNotifier {
|
|
|
91
91
|
return;
|
|
92
92
|
if (event.type !== 'add' && event.type !== 'change')
|
|
93
93
|
return;
|
|
94
|
-
|
|
95
|
-
const
|
|
94
|
+
// Normalize path for robust comparison (handles Windows backslashes)
|
|
95
|
+
const normalizedPath = event.path.replace(/\\/g, '/').toLowerCase();
|
|
96
|
+
const isIgnoredFile = this.#fileAlertIgnoreSubstrings.some((segment) => normalizedPath.includes(segment.replace(/\\/g, '/').toLowerCase()));
|
|
96
97
|
if (isIgnoredFile) {
|
|
97
98
|
await logThought(`[ProactiveNotifier] Ignored modification event for system file: ${event.path}`);
|
|
98
99
|
return;
|
|
@@ -9,34 +9,42 @@ const TASK_HINT_PATTERN = /\b(todo|task|implement|fix|build|create|refactor|ship
|
|
|
9
9
|
const MAX_RELATION_RECONCILIATION = 12;
|
|
10
10
|
const MAX_GRAPH_TRAVERSAL_DEPTH = 2;
|
|
11
11
|
export async function indexConversationTurn(sessionId, role, content) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const chunks = chunkText(normalized);
|
|
17
|
-
let previousNodeId = null;
|
|
18
|
-
for (const chunk of chunks) {
|
|
19
|
-
const taggedChunk = `${role.toUpperCase()}: ${chunk}`;
|
|
20
|
-
const embedding = await embeddingService.embedText(taggedChunk);
|
|
21
|
-
if (!embedding) {
|
|
22
|
-
continue;
|
|
12
|
+
try {
|
|
13
|
+
const normalized = content.trim();
|
|
14
|
+
if (!normalized) {
|
|
15
|
+
return;
|
|
23
16
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
const chunks = chunkText(normalized);
|
|
18
|
+
let previousNodeId = null;
|
|
19
|
+
// Limit indexing to first 2 chunks to prevent long hangs during indexing
|
|
20
|
+
const limitedChunks = chunks.slice(0, 2);
|
|
21
|
+
for (const chunk of limitedChunks) {
|
|
22
|
+
const taggedChunk = `${role.toUpperCase()}: ${chunk}`;
|
|
23
|
+
const embedding = await embeddingService.embedText(taggedChunk);
|
|
24
|
+
if (!embedding) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const memoryRowId = saveMemoryEmbedding(sessionId, taggedChunk, embedding);
|
|
28
|
+
const node = buildReasoningNode(sessionId, role, taggedChunk);
|
|
29
|
+
upsertReasoningNode(node);
|
|
30
|
+
linkMemoryProvenance(memoryRowId, node.nodeId, sessionId);
|
|
31
|
+
if (previousNodeId && previousNodeId !== node.nodeId) {
|
|
32
|
+
upsertReasoningEdge({
|
|
33
|
+
edgeId: stableId('edge', `${previousNodeId}|${node.nodeId}|derived_from`),
|
|
34
|
+
fromNodeId: previousNodeId,
|
|
35
|
+
toNodeId: node.nodeId,
|
|
36
|
+
relation: 'derived_from',
|
|
37
|
+
weight: 0.55,
|
|
38
|
+
provenance: `session:${sessionId}:turn-sequence`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
previousNodeId = node.nodeId;
|
|
42
|
+
reconcileClaimRelations(node);
|
|
37
43
|
}
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
47
|
+
console.warn(`[SemanticMemory] Failed to index turn for session ${sessionId}: ${message}`);
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
export async function retrieveEvidenceAwareMemoryContext(sessionId, prompt, topK = 5) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twinclaw",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "Eagle-eyed agentic AI gateway with multi-modal hooks and proactive memory.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"axios": "^1.13.5",
|
|
44
44
|
"better-sqlite3": "^12.6.2",
|
|
45
45
|
"blessed": "^0.1.81",
|
|
46
|
-
"blessed-contrib": "^
|
|
46
|
+
"blessed-contrib": "^4.11.0",
|
|
47
47
|
"chokidar": "^5.0.0",
|
|
48
48
|
"express": "^5.2.1",
|
|
49
49
|
"groq-sdk": "^0.37.0",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"ts-node": "^10.9.2",
|
|
58
58
|
"tsx": "^4.21.0",
|
|
59
59
|
"typescript": "^5.9.3",
|
|
60
|
-
"whatsapp-web.js": "^1.
|
|
60
|
+
"whatsapp-web.js": "^1.34.6",
|
|
61
61
|
"ws": "^8.19.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
@@ -76,7 +76,11 @@
|
|
|
76
76
|
"overrides": {
|
|
77
77
|
"tar-fs": "^3.1.1",
|
|
78
78
|
"ws": "^8.19.0",
|
|
79
|
-
"
|
|
79
|
+
"inflight": "npm:lru-cache@^11.0.0",
|
|
80
|
+
"rimraf": "^6.0.1",
|
|
81
|
+
"glob": "^11.0.1",
|
|
82
|
+
"uuid": "^11.1.0",
|
|
83
|
+
"request": "npm:@cypress/request@^3.0.10",
|
|
80
84
|
"request-promise": "npm:@cypress/request-promise@^5.0.0"
|
|
81
85
|
}
|
|
82
86
|
}
|