@hashgraphonline/conversational-agent 0.2.104 → 0.2.106

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.
Files changed (117) hide show
  1. package/cli/readme.md +181 -0
  2. package/dist/cjs/conversational-agent.d.ts +11 -2
  3. package/dist/cjs/core/tool-registry.d.ts +3 -0
  4. package/dist/cjs/forms/field-guidance-registry.d.ts +33 -0
  5. package/dist/cjs/index.cjs +1 -1
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/index.d.ts +1 -0
  8. package/dist/cjs/plugins/inscribe/InscribePlugin.d.ts +1 -0
  9. package/dist/cjs/runtime/wallet-bridge.d.ts +23 -0
  10. package/dist/cjs/signers/browser-signer.d.ts +32 -0
  11. package/dist/esm/index.js +3 -0
  12. package/dist/esm/index.js.map +1 -1
  13. package/dist/esm/index10.js +13 -5
  14. package/dist/esm/index10.js.map +1 -1
  15. package/dist/esm/index13.js +157 -179
  16. package/dist/esm/index13.js.map +1 -1
  17. package/dist/esm/index2.js +29 -25
  18. package/dist/esm/index2.js.map +1 -1
  19. package/dist/esm/index21.js +1 -1
  20. package/dist/esm/index23.js +3 -3
  21. package/dist/esm/index3.js.map +1 -1
  22. package/dist/esm/index33.js +5 -5
  23. package/dist/esm/index33.js.map +1 -1
  24. package/dist/esm/index36.js +8 -45
  25. package/dist/esm/index36.js.map +1 -1
  26. package/dist/esm/index37.js +41 -102
  27. package/dist/esm/index37.js.map +1 -1
  28. package/dist/esm/index38.js +107 -21
  29. package/dist/esm/index38.js.map +1 -1
  30. package/dist/esm/index39.js +63 -24
  31. package/dist/esm/index39.js.map +1 -1
  32. package/dist/esm/index4.js +43 -0
  33. package/dist/esm/index4.js.map +1 -1
  34. package/dist/esm/index40.js +21 -12
  35. package/dist/esm/index40.js.map +1 -1
  36. package/dist/esm/index41.js +11 -4
  37. package/dist/esm/index41.js.map +1 -1
  38. package/dist/esm/index42.js +7 -255
  39. package/dist/esm/index42.js.map +1 -1
  40. package/dist/esm/index43.js +5 -184
  41. package/dist/esm/index43.js.map +1 -1
  42. package/dist/esm/index44.js +271 -7
  43. package/dist/esm/index44.js.map +1 -1
  44. package/dist/esm/index45.js +174 -82
  45. package/dist/esm/index45.js.map +1 -1
  46. package/dist/esm/index46.js +30 -0
  47. package/dist/esm/index46.js.map +1 -0
  48. package/dist/esm/index47.js +95 -0
  49. package/dist/esm/index47.js.map +1 -0
  50. package/dist/esm/index5.js +2 -2
  51. package/dist/esm/index6.js +111 -23
  52. package/dist/esm/index6.js.map +1 -1
  53. package/dist/types/conversational-agent.d.ts +11 -2
  54. package/dist/types/core/tool-registry.d.ts +3 -0
  55. package/dist/types/forms/field-guidance-registry.d.ts +33 -0
  56. package/dist/types/index.d.ts +1 -0
  57. package/dist/types/plugins/inscribe/InscribePlugin.d.ts +1 -0
  58. package/dist/types/runtime/wallet-bridge.d.ts +23 -0
  59. package/dist/types/signers/browser-signer.d.ts +32 -0
  60. package/package.json +43 -32
  61. package/src/conversational-agent.ts +139 -39
  62. package/src/core/tool-registry.ts +25 -0
  63. package/src/forms/field-guidance-registry.ts +215 -188
  64. package/src/forms/form-generator.ts +28 -12
  65. package/src/index.ts +1 -0
  66. package/src/langchain/langchain-agent.ts +1 -1
  67. package/src/plugins/hcs-10/HCS10Plugin.ts +32 -28
  68. package/src/plugins/hcs-2/HCS2Plugin.ts +4 -2
  69. package/src/plugins/inscribe/InscribePlugin.ts +47 -2
  70. package/src/runtime/wallet-bridge.ts +41 -0
  71. package/src/signers/browser-signer.ts +112 -0
  72. package/cli/dist/CLIApp.d.ts +0 -9
  73. package/cli/dist/CLIApp.js +0 -127
  74. package/cli/dist/LocalConversationalAgent.d.ts +0 -37
  75. package/cli/dist/LocalConversationalAgent.js +0 -58
  76. package/cli/dist/app.d.ts +0 -16
  77. package/cli/dist/app.js +0 -13
  78. package/cli/dist/cli.d.ts +0 -2
  79. package/cli/dist/cli.js +0 -51
  80. package/cli/dist/components/AppContainer.d.ts +0 -16
  81. package/cli/dist/components/AppContainer.js +0 -24
  82. package/cli/dist/components/AppScreens.d.ts +0 -2
  83. package/cli/dist/components/AppScreens.js +0 -259
  84. package/cli/dist/components/ChatScreen.d.ts +0 -15
  85. package/cli/dist/components/ChatScreen.js +0 -39
  86. package/cli/dist/components/DebugLoadingScreen.d.ts +0 -5
  87. package/cli/dist/components/DebugLoadingScreen.js +0 -31
  88. package/cli/dist/components/LoadingScreen.d.ts +0 -2
  89. package/cli/dist/components/LoadingScreen.js +0 -16
  90. package/cli/dist/components/LoadingScreenDebug.d.ts +0 -5
  91. package/cli/dist/components/LoadingScreenDebug.js +0 -27
  92. package/cli/dist/components/MCPConfigScreen.d.ts +0 -28
  93. package/cli/dist/components/MCPConfigScreen.js +0 -168
  94. package/cli/dist/components/ScreenRouter.d.ts +0 -12
  95. package/cli/dist/components/ScreenRouter.js +0 -22
  96. package/cli/dist/components/SetupScreen.d.ts +0 -15
  97. package/cli/dist/components/SetupScreen.js +0 -65
  98. package/cli/dist/components/SingleLoadingScreen.d.ts +0 -5
  99. package/cli/dist/components/SingleLoadingScreen.js +0 -27
  100. package/cli/dist/components/StatusBadge.d.ts +0 -7
  101. package/cli/dist/components/StatusBadge.js +0 -28
  102. package/cli/dist/components/TerminalWindow.d.ts +0 -8
  103. package/cli/dist/components/TerminalWindow.js +0 -24
  104. package/cli/dist/components/WelcomeScreen.d.ts +0 -11
  105. package/cli/dist/components/WelcomeScreen.js +0 -47
  106. package/cli/dist/context/AppContext.d.ts +0 -68
  107. package/cli/dist/context/AppContext.js +0 -363
  108. package/cli/dist/hooks/useInitializeAgent.d.ts +0 -19
  109. package/cli/dist/hooks/useInitializeAgent.js +0 -28
  110. package/cli/dist/hooks/useStableState.d.ts +0 -38
  111. package/cli/dist/hooks/useStableState.js +0 -68
  112. package/cli/dist/managers/AgentManager.d.ts +0 -57
  113. package/cli/dist/managers/AgentManager.js +0 -119
  114. package/cli/dist/managers/ConfigManager.d.ts +0 -53
  115. package/cli/dist/managers/ConfigManager.js +0 -173
  116. package/cli/dist/types.d.ts +0 -31
  117. package/cli/dist/types.js +0 -19
@@ -1,259 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { Box, Text, useApp, useInput } from 'ink';
3
- import TextInput from 'ink-text-input';
4
- import SelectInput from 'ink-select-input';
5
- import { WelcomeScreen } from './WelcomeScreen.js';
6
- import { ChatScreen } from './ChatScreen.js';
7
- import { LoadingScreen } from './LoadingScreen.js';
8
- import { TerminalWindow } from './TerminalWindow.js';
9
- import { StatusBadge } from './StatusBadge.js';
10
- import { BRAND_COLORS } from '../types.js';
11
- import { useAppContext } from '../context/AppContext.js';
12
- import { saveMCPConfig, getMCPConfigPath } from '../context/AppContext.js';
13
- import { MCPServers } from '@hashgraphonline/conversational-agent';
14
- export const AppScreens = () => {
15
- const { state, actions } = useAppContext();
16
- const { exit } = useApp();
17
- const [showLogs] = useState(false);
18
- const fields = ['accountId', 'privateKey', 'network', 'openAIApiKey'];
19
- useInput((_, key) => {
20
- if (state.screen === 'mcp-config' && key.escape) {
21
- if (state.mcpConfig.addingCustom) {
22
- actions.setMcpConfig({
23
- addingCustom: false,
24
- newServerName: '',
25
- newServerCommand: '',
26
- newServerArgs: '',
27
- newServerEnv: '',
28
- currentField: 0,
29
- });
30
- }
31
- else if (state.editingFilesystemPath) {
32
- actions.setEditingFilesystemPath(false);
33
- }
34
- }
35
- });
36
- if (state.screen === 'loading') {
37
- return React.createElement(LoadingScreen, null);
38
- }
39
- if (state.screen === 'setup') {
40
- return (React.createElement(TerminalWindow, { title: "Configuration" },
41
- React.createElement(Box, { flexDirection: "column" },
42
- React.createElement(Box, { marginBottom: 1 },
43
- React.createElement(StatusBadge, { status: "info" }),
44
- React.createElement(Text, null, "Configure your Hedera account credentials")),
45
- fields.map((field, index) => (React.createElement(Box, { key: field, marginY: 1 },
46
- React.createElement(Box, { width: 20 },
47
- React.createElement(Text, { color: state.currentField === index
48
- ? BRAND_COLORS.blue
49
- : BRAND_COLORS.hedera.smoke },
50
- field === 'accountId' && 'Account ID:',
51
- field === 'privateKey' && 'Private Key:',
52
- field === 'network' && 'Network:',
53
- field === 'openAIApiKey' && 'OpenAI Key:')),
54
- state.currentField === index ? (field === 'network' ? (React.createElement(SelectInput, { items: [
55
- { label: 'Testnet', value: 'testnet' },
56
- { label: 'Mainnet', value: 'mainnet' },
57
- ], initialIndex: state.config.network === 'testnet' ? 0 : 1, onSelect: item => {
58
- actions.updateConfigField('network', item.value);
59
- if (state.currentField < fields.length - 1) {
60
- actions.setCurrentField(state.currentField + 1);
61
- }
62
- } })) : (React.createElement(TextInput, { value: state.config[field], onChange: value => actions.updateConfigField(field, value), onSubmit: () => {
63
- if (state.currentField < fields.length - 1) {
64
- actions.setCurrentField(state.currentField + 1);
65
- }
66
- else {
67
- actions.initializeAgent();
68
- }
69
- }, mask: field === 'privateKey' || field === 'openAIApiKey'
70
- ? '*'
71
- : undefined }))) : (React.createElement(Text, { color: BRAND_COLORS.hedera.smoke }, field === 'network'
72
- ? state.config[field]
73
- : state.config[field]
74
- ? '••••••••'
75
- : '(not set)'))))),
76
- state.error && (React.createElement(Box, { marginTop: 2 },
77
- React.createElement(StatusBadge, { status: "error" }),
78
- React.createElement(Text, { color: "red" }, state.error))),
79
- React.createElement(Box, { marginTop: 2 },
80
- React.createElement(Text, { dimColor: true }, "Press Tab to navigate fields, Enter to submit"),
81
- React.createElement(Text, { dimColor: true }, "Complete all fields and press Enter on the last field to save and start")))));
82
- }
83
- if (state.screen === 'mcp-config') {
84
- if (state.editingFilesystemPath) {
85
- return (React.createElement(TerminalWindow, { title: "Edit Filesystem Path" },
86
- React.createElement(Box, { flexDirection: "column" },
87
- React.createElement(Box, { marginBottom: 2 },
88
- React.createElement(Text, null, "Enter the directory path for the filesystem server:")),
89
- React.createElement(TextInput, { value: state.mcpConfig.filesystemPath, onChange: value => actions.setMcpConfig({ filesystemPath: value }), onSubmit: () => {
90
- actions.setEditingFilesystemPath(false);
91
- const servers = [];
92
- if (state.mcpConfig.enableFilesystem) {
93
- servers.push(MCPServers.filesystem(state.mcpConfig.filesystemPath));
94
- }
95
- servers.push(...state.mcpConfig.customServers);
96
- saveMCPConfig(servers);
97
- }, placeholder: process.cwd() }),
98
- React.createElement(Box, { marginTop: 2 },
99
- React.createElement(Text, { dimColor: true }, "Press Enter to save, Escape to cancel")))));
100
- }
101
- if (state.mcpConfig.addingCustom) {
102
- const customFields = [
103
- 'newServerName',
104
- 'newServerCommand',
105
- 'newServerArgs',
106
- 'newServerEnv',
107
- ];
108
- const fieldLabels = [
109
- 'Server Name:',
110
- 'Command:',
111
- 'Arguments (comma-separated):',
112
- 'Environment Variables (KEY=value, comma-separated):',
113
- ];
114
- const placeholders = [
115
- 'my-server',
116
- 'npx',
117
- '-y, @modelcontextprotocol/server-github',
118
- 'MCP_LOG_LEVEL=info, GIT_SIGN_COMMITS=false',
119
- ];
120
- return (React.createElement(TerminalWindow, { title: "Add Custom MCP Server" },
121
- React.createElement(Box, { flexDirection: "column" },
122
- customFields.map((field, index) => (React.createElement(Box, { key: field, marginY: 1 },
123
- React.createElement(Text, { color: state.mcpConfig.currentField === index
124
- ? BRAND_COLORS.blue
125
- : BRAND_COLORS.hedera.smoke }, fieldLabels[index]),
126
- state.mcpConfig.currentField === index ? (React.createElement(TextInput, { value: state.mcpConfig[field], onChange: value => actions.setMcpConfig({ [field]: value }), onSubmit: () => {
127
- if (index < customFields.length - 1) {
128
- actions.setMcpConfig({ currentField: index + 1 });
129
- }
130
- else if (state.mcpConfig.newServerName &&
131
- state.mcpConfig.newServerCommand) {
132
- const env = {};
133
- if (state.mcpConfig.newServerEnv) {
134
- state.mcpConfig.newServerEnv.split(',').forEach(envVar => {
135
- const [key, value] = envVar.trim().split('=');
136
- if (key && value) {
137
- env[key] = value;
138
- }
139
- });
140
- }
141
- const newServer = {
142
- name: state.mcpConfig.newServerName,
143
- command: state.mcpConfig.newServerCommand,
144
- args: state.mcpConfig.newServerArgs
145
- .split(',')
146
- .map(arg => arg.trim())
147
- .filter(Boolean),
148
- transport: 'stdio',
149
- autoConnect: true,
150
- ...(Object.keys(env).length > 0 && { env }),
151
- };
152
- const newCustomServers = [...state.mcpConfig.customServers, newServer];
153
- actions.setMcpConfig({
154
- customServers: newCustomServers,
155
- addingCustom: false,
156
- newServerName: '',
157
- newServerCommand: '',
158
- newServerArgs: '',
159
- newServerEnv: '',
160
- currentField: 0,
161
- });
162
- const servers = [];
163
- if (state.mcpConfig.enableFilesystem) {
164
- servers.push(MCPServers.filesystem(state.mcpConfig.filesystemPath));
165
- }
166
- servers.push(...newCustomServers);
167
- saveMCPConfig(servers);
168
- }
169
- }, placeholder: placeholders[index] })) : (React.createElement(Text, { color: BRAND_COLORS.hedera.smoke }, state.mcpConfig[field] ||
170
- `(${placeholders[index]})`))))),
171
- React.createElement(Box, { marginTop: 2 },
172
- React.createElement(Text, { dimColor: true }, "Press Tab or Enter to move between fields"),
173
- React.createElement(Text, { dimColor: true }, "Press Enter on the last field to add the server"),
174
- React.createElement(Text, { dimColor: true }, "Press Escape to cancel")))));
175
- }
176
- const menuItems = [
177
- {
178
- label: `Filesystem Server: ${state.mcpConfig.enableFilesystem ? 'Enabled' : 'Disabled'}`,
179
- value: 'filesystem',
180
- },
181
- ];
182
- if (state.mcpConfig.enableFilesystem) {
183
- menuItems.push({
184
- label: `Filesystem Path: ${state.mcpConfig.filesystemPath}`,
185
- value: 'filesystem-path',
186
- });
187
- }
188
- state.mcpConfig.customServers.forEach((server, index) => {
189
- menuItems.push({
190
- label: `${server.name} (${server.command})`,
191
- value: `custom-${index}`,
192
- });
193
- });
194
- menuItems.push({ label: 'Add Custom Server', value: 'add-custom' }, { label: 'Done (changes auto-saved)', value: 'save' }, { label: 'Back to Menu', value: 'back' });
195
- return (React.createElement(TerminalWindow, { title: "MCP Server Configuration" },
196
- React.createElement(Box, { flexDirection: "column" },
197
- React.createElement(Box, { marginBottom: 2 },
198
- React.createElement(StatusBadge, { status: "info" }),
199
- React.createElement(Text, null, "Configure Model Context Protocol servers")),
200
- React.createElement(SelectInput, { items: menuItems, onSelect: item => {
201
- if (item.value === 'filesystem') {
202
- const enableFilesystem = !state.mcpConfig.enableFilesystem;
203
- actions.setMcpConfig({ enableFilesystem });
204
- const servers = [];
205
- if (enableFilesystem) {
206
- servers.push(MCPServers.filesystem(state.mcpConfig.filesystemPath));
207
- }
208
- servers.push(...state.mcpConfig.customServers);
209
- saveMCPConfig(servers);
210
- }
211
- else if (item.value === 'filesystem-path') {
212
- actions.setEditingFilesystemPath(true);
213
- }
214
- else if (item.value === 'add-custom') {
215
- actions.setMcpConfig({ addingCustom: true });
216
- }
217
- else if (item.value === 'save') {
218
- const servers = [];
219
- if (state.mcpConfig.enableFilesystem) {
220
- servers.push(MCPServers.filesystem(state.mcpConfig.filesystemPath));
221
- }
222
- servers.push(...state.mcpConfig.customServers);
223
- saveMCPConfig(servers);
224
- const updatedConfig = {
225
- ...state.config,
226
- mcpServers: servers,
227
- };
228
- actions.setConfig(updatedConfig);
229
- actions.setScreen('welcome');
230
- }
231
- else if (item.value === 'back') {
232
- actions.setScreen('welcome');
233
- }
234
- else if (item.value.startsWith('custom-')) {
235
- const index = parseInt(item.value.replace('custom-', ''));
236
- const newCustomServers = state.mcpConfig.customServers.filter((_, i) => i !== index);
237
- actions.setMcpConfig({ customServers: newCustomServers });
238
- const servers = [];
239
- if (state.mcpConfig.enableFilesystem) {
240
- servers.push(MCPServers.filesystem(state.mcpConfig.filesystemPath));
241
- }
242
- servers.push(...newCustomServers);
243
- saveMCPConfig(servers);
244
- }
245
- } }),
246
- React.createElement(Box, { marginY: 2 },
247
- React.createElement(Text, { dimColor: true }, "Press Enter to toggle/edit servers, or select actions"),
248
- state.mcpConfig.enableFilesystem && (React.createElement(Text, { dimColor: true },
249
- "Filesystem path: ",
250
- state.mcpConfig.filesystemPath)),
251
- React.createElement(Text, { dimColor: true },
252
- "Config saved to: ",
253
- getMCPConfigPath())))));
254
- }
255
- if (state.screen === 'chat') {
256
- return (React.createElement(ChatScreen, { config: state.config, messages: state.messages, input: state.input, isLoading: state.isLoading, setInput: actions.setInput, sendMessage: actions.sendMessage, showLogs: showLogs, logs: state.logs }));
257
- }
258
- return (React.createElement(WelcomeScreen, { config: state.config, onExit: exit, onInitializeAgent: actions.initializeAgent, onSetScreen: actions.setScreen, isLoading: state.isLoading, agent: state.agent }));
259
- };
@@ -1,15 +0,0 @@
1
- import React from 'react';
2
- import { type Config, type Message } from '../types';
3
- /**
4
- * Chat screen component
5
- */
6
- export declare const ChatScreen: React.FC<{
7
- config: Config;
8
- messages: Message[];
9
- input: string;
10
- isLoading: boolean;
11
- setInput: (value: string) => void;
12
- sendMessage: (message: string) => void;
13
- showLogs: boolean;
14
- logs: string[];
15
- }>;
@@ -1,39 +0,0 @@
1
- import React from 'react';
2
- import { Box, Text } from 'ink';
3
- import TextInput from 'ink-text-input';
4
- import Spinner from 'ink-spinner';
5
- import { TerminalWindow } from './TerminalWindow.js';
6
- import { StatusBadge } from './StatusBadge.js';
7
- import { BRAND_COLORS } from '../types.js';
8
- /**
9
- * Chat screen component
10
- */
11
- export const ChatScreen = React.memo(({ config, messages, input, isLoading, setInput, sendMessage, showLogs, logs, }) => {
12
- return (React.createElement(TerminalWindow, { title: `Conversational Agent Chat (${config.network})` },
13
- React.createElement(Box, { flexDirection: "column", minHeight: 25 },
14
- showLogs && (React.createElement(Box, { borderStyle: "single", borderColor: BRAND_COLORS.dark, marginBottom: 1, padding: 1, height: 10, flexDirection: "column", overflow: "hidden" },
15
- React.createElement(Box, { marginBottom: 1 },
16
- React.createElement(Text, { color: BRAND_COLORS.hedera.smoke, bold: true }, "\uD83D\uDCCB Logs")),
17
- React.createElement(Box, { flexDirection: "column", overflow: "hidden" }, logs.slice(-8).map((log, i) => (React.createElement(Text, { key: i, color: BRAND_COLORS.comments, dimColor: true, wrap: "truncate" }, log)))))),
18
- React.createElement(Box, { flexDirection: "column", flexGrow: 1, marginBottom: 1, overflow: "hidden" }, messages.slice(-15).map((msg, index) => (React.createElement(Box, { key: `${msg.timestamp.getTime()}-${index}`, marginBottom: 1 },
19
- msg.role === 'user' && (React.createElement(Box, { flexDirection: "column" },
20
- React.createElement(Box, null,
21
- React.createElement(Text, { color: BRAND_COLORS.green }, "$ "),
22
- React.createElement(Text, { wrap: "wrap" }, msg.content)))),
23
- msg.role === 'assistant' && (React.createElement(Box, { flexDirection: "column" },
24
- React.createElement(Box, null,
25
- React.createElement(Text, { color: BRAND_COLORS.blue }, "\u2192 "),
26
- React.createElement(Text, { wrap: "wrap" }, msg.content)))),
27
- msg.role === 'system' && (React.createElement(Box, { flexDirection: "column" },
28
- React.createElement(Box, null,
29
- React.createElement(StatusBadge, { status: "info" }),
30
- React.createElement(Text, { color: BRAND_COLORS.hedera.smoke, wrap: "wrap" }, msg.content)))))))),
31
- React.createElement(Box, { borderStyle: "single", borderTop: true, borderColor: BRAND_COLORS.dark, paddingTop: 1, paddingX: 1 }, isLoading ? (React.createElement(Box, null,
32
- React.createElement(Spinner, { type: "dots" }),
33
- React.createElement(Text, { color: BRAND_COLORS.hedera.smoke }, " Processing..."))) : (React.createElement(Box, { flexDirection: "row", width: "100%" },
34
- React.createElement(Text, { color: BRAND_COLORS.green }, "$ "),
35
- React.createElement(Box, { flexGrow: 1 },
36
- React.createElement(TextInput, { value: input, onChange: setInput, onSubmit: sendMessage, placeholder: "Type your message..." }))))),
37
- React.createElement(Box, { marginTop: 1, paddingX: 1 },
38
- React.createElement(Text, { dimColor: true }, "Ctrl+C to exit, ESC to return to menu, L to toggle logs")))));
39
- });
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- /**
3
- * Debug loading screen to trace double rendering issue
4
- */
5
- export declare const DebugLoadingScreen: React.FC;
@@ -1,31 +0,0 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import { Box, Text } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import { BRAND_COLORS } from '../types.js';
5
- let globalRenderCount = 0;
6
- let globalInstanceCount = 0;
7
- /**
8
- * Debug loading screen to trace double rendering issue
9
- */
10
- export const DebugLoadingScreen = () => {
11
- const instanceId = useRef(++globalInstanceCount);
12
- const renderCount = useRef(0);
13
- const mountTime = useRef(Date.now());
14
- renderCount.current++;
15
- globalRenderCount++;
16
- console.error(`[LOADING-${instanceId.current}] Render #${renderCount.current} (Global: ${globalRenderCount}) at ${Date.now() - mountTime.current}ms`);
17
- useEffect(() => {
18
- console.error(`[LOADING-${instanceId.current}] MOUNTED`);
19
- console.error(new Error('Mount Stack Trace').stack);
20
- return () => {
21
- console.error(`[LOADING-${instanceId.current}] UNMOUNTED after ${renderCount.current} renders`);
22
- };
23
- }, []);
24
- return (React.createElement(Box, { flexDirection: "column", alignItems: "center", paddingY: 4 },
25
- React.createElement(Box, { marginBottom: 2 },
26
- React.createElement(Text, { color: BRAND_COLORS.blue }, "Initializing "),
27
- React.createElement(Text, { color: BRAND_COLORS.purple }, "Hashgraph "),
28
- React.createElement(Text, { color: BRAND_COLORS.green }, "Online "),
29
- React.createElement(Text, { color: BRAND_COLORS.blue }, "Agent...")),
30
- React.createElement(Spinner, { type: "dots" })));
31
- };
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare const LoadingScreen: React.FC;
@@ -1,16 +0,0 @@
1
- import React, { useEffect } from 'react';
2
- import { Box, Text, useStdout } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import { BRAND_COLORS } from '../types.js';
5
- export const LoadingScreen = () => {
6
- const { write } = useStdout();
7
- useEffect(() => {
8
- write('\x1Bc');
9
- }, [write]);
10
- return (React.createElement(Box, { flexDirection: "column", alignItems: "center", paddingY: 4 },
11
- React.createElement(Box, { marginBottom: 2 },
12
- React.createElement(Text, { color: BRAND_COLORS.blue }, "Initializing "),
13
- React.createElement(Text, { color: BRAND_COLORS.purple }, "Conversational "),
14
- React.createElement(Text, { color: BRAND_COLORS.green }, "Agent...")),
15
- React.createElement(Spinner, { type: "dots" })));
16
- };
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- /**
3
- * Loading screen component with debug logging
4
- */
5
- export declare const LoadingScreenDebug: React.FC;
@@ -1,27 +0,0 @@
1
- import React, { useEffect } from 'react';
2
- import { Box, Text, Static } from 'ink';
3
- import Spinner from 'ink-spinner';
4
- import { BRAND_COLORS } from '../types.js';
5
- let renderCount = 0;
6
- /**
7
- * Loading screen component with debug logging
8
- */
9
- export const LoadingScreenDebug = () => {
10
- renderCount++;
11
- useEffect(() => {
12
- console.error(`[LOADING] Mounted - render #${renderCount}`);
13
- return () => {
14
- console.error(`[LOADING] Unmounted - after ${renderCount} renders`);
15
- };
16
- }, []);
17
- useEffect(() => {
18
- console.error(`[LOADING] Render #${renderCount}`);
19
- });
20
- return (React.createElement(Box, { flexDirection: "column", alignItems: "center", paddingY: 4 },
21
- React.createElement(Static, { items: [{ id: '1' }] }, () => (React.createElement(Box, { marginBottom: 2 },
22
- React.createElement(Text, { color: BRAND_COLORS.blue }, "Initializing "),
23
- React.createElement(Text, { color: BRAND_COLORS.purple }, "Hashgraph "),
24
- React.createElement(Text, { color: BRAND_COLORS.green }, "Online "),
25
- React.createElement(Text, { color: BRAND_COLORS.blue }, "Agent...")))),
26
- React.createElement(Spinner, { type: "dots" })));
27
- };
@@ -1,28 +0,0 @@
1
- import React from 'react';
2
- import { type Screen } from '../types';
3
- import { type MCPServerConfig } from '@hashgraphonline/conversational-agent';
4
- interface MCPConfig {
5
- enableFilesystem: boolean;
6
- filesystemPath: string;
7
- customServers: MCPServerConfig[];
8
- addingCustom: boolean;
9
- newServerName: string;
10
- newServerCommand: string;
11
- newServerArgs: string;
12
- newServerEnv: string;
13
- currentField: number;
14
- }
15
- interface Props {
16
- mcpConfig: MCPConfig;
17
- editingFilesystemPath: boolean;
18
- onSetMcpConfig: (config: Partial<MCPConfig>) => void;
19
- onSetEditingFilesystemPath: (editing: boolean) => void;
20
- onSetScreen: (screen: Screen) => void;
21
- onSaveMCPConfig: () => void;
22
- getMCPConfigPath: () => string;
23
- }
24
- /**
25
- * MCP Configuration screen
26
- */
27
- export declare const MCPConfigScreen: React.FC<Props>;
28
- export {};
@@ -1,168 +0,0 @@
1
- import React from 'react';
2
- import { Box, Text, useInput } from 'ink';
3
- import TextInput from 'ink-text-input';
4
- import SelectInput from 'ink-select-input';
5
- import { TerminalWindow } from './TerminalWindow.js';
6
- import { StatusBadge } from './StatusBadge.js';
7
- import { BRAND_COLORS } from '../types.js';
8
- /**
9
- * MCP Configuration screen
10
- */
11
- export const MCPConfigScreen = ({ mcpConfig, editingFilesystemPath, onSetMcpConfig, onSetEditingFilesystemPath, onSetScreen, onSaveMCPConfig, getMCPConfigPath, }) => {
12
- useInput((_, key) => {
13
- if (key.escape) {
14
- if (mcpConfig.addingCustom) {
15
- onSetMcpConfig({
16
- addingCustom: false,
17
- newServerName: '',
18
- newServerCommand: '',
19
- newServerArgs: '',
20
- newServerEnv: '',
21
- currentField: 0,
22
- });
23
- }
24
- else if (editingFilesystemPath) {
25
- onSetEditingFilesystemPath(false);
26
- }
27
- }
28
- });
29
- if (editingFilesystemPath) {
30
- return (React.createElement(TerminalWindow, { title: "Edit Filesystem Path" },
31
- React.createElement(Box, { flexDirection: "column" },
32
- React.createElement(Box, { marginBottom: 2 },
33
- React.createElement(Text, null, "Enter the directory path for the filesystem server:")),
34
- React.createElement(TextInput, { value: mcpConfig.filesystemPath, onChange: value => onSetMcpConfig({ filesystemPath: value }), onSubmit: () => {
35
- onSetEditingFilesystemPath(false);
36
- onSaveMCPConfig();
37
- }, placeholder: process.cwd() }),
38
- React.createElement(Box, { marginTop: 2 },
39
- React.createElement(Text, { dimColor: true }, "Press Enter to save, Escape to cancel")))));
40
- }
41
- if (mcpConfig.addingCustom) {
42
- const customFields = [
43
- 'newServerName',
44
- 'newServerCommand',
45
- 'newServerArgs',
46
- 'newServerEnv',
47
- ];
48
- const fieldLabels = [
49
- 'Server Name:',
50
- 'Command:',
51
- 'Arguments (comma-separated):',
52
- 'Environment Variables (KEY=value, comma-separated):',
53
- ];
54
- const placeholders = [
55
- 'my-server',
56
- 'npx',
57
- '-y, @modelcontextprotocol/server-github',
58
- 'MCP_LOG_LEVEL=info, GIT_SIGN_COMMITS=false',
59
- ];
60
- return (React.createElement(TerminalWindow, { title: "Add Custom MCP Server" },
61
- React.createElement(Box, { flexDirection: "column" },
62
- customFields.map((field, index) => (React.createElement(Box, { key: field, marginY: 1 },
63
- React.createElement(Text, { color: mcpConfig.currentField === index
64
- ? BRAND_COLORS.blue
65
- : BRAND_COLORS.hedera.smoke }, fieldLabels[index]),
66
- mcpConfig.currentField === index ? (React.createElement(TextInput, { value: mcpConfig[field], onChange: value => onSetMcpConfig({ [field]: value }), onSubmit: () => {
67
- if (index < customFields.length - 1) {
68
- onSetMcpConfig({ currentField: index + 1 });
69
- }
70
- else if (mcpConfig.newServerName &&
71
- mcpConfig.newServerCommand) {
72
- const env = {};
73
- if (mcpConfig.newServerEnv) {
74
- mcpConfig.newServerEnv.split(',').forEach(envVar => {
75
- const [key, value] = envVar.trim().split('=');
76
- if (key && value) {
77
- env[key] = value;
78
- }
79
- });
80
- }
81
- const newServer = {
82
- name: mcpConfig.newServerName,
83
- command: mcpConfig.newServerCommand,
84
- args: mcpConfig.newServerArgs
85
- .split(',')
86
- .map(arg => arg.trim())
87
- .filter(Boolean),
88
- transport: 'stdio',
89
- autoConnect: true,
90
- ...(Object.keys(env).length > 0 && { env }),
91
- };
92
- const newCustomServers = [...mcpConfig.customServers, newServer];
93
- onSetMcpConfig({
94
- customServers: newCustomServers,
95
- addingCustom: false,
96
- newServerName: '',
97
- newServerCommand: '',
98
- newServerArgs: '',
99
- newServerEnv: '',
100
- currentField: 0,
101
- });
102
- onSaveMCPConfig();
103
- }
104
- }, placeholder: placeholders[index] })) : (React.createElement(Text, { color: BRAND_COLORS.hedera.smoke }, String(mcpConfig[field] || `(${placeholders[index]})`)))))),
105
- React.createElement(Box, { marginTop: 2 },
106
- React.createElement(Text, { dimColor: true }, "Press Tab or Enter to move between fields"),
107
- React.createElement(Text, { dimColor: true }, "Press Enter on the last field to add the server"),
108
- React.createElement(Text, { dimColor: true }, "Press Escape to cancel")))));
109
- }
110
- const menuItems = [
111
- {
112
- label: `Filesystem Server: ${mcpConfig.enableFilesystem ? 'Enabled' : 'Disabled'}`,
113
- value: 'filesystem',
114
- },
115
- ];
116
- if (mcpConfig.enableFilesystem) {
117
- menuItems.push({
118
- label: `Filesystem Path: ${mcpConfig.filesystemPath}`,
119
- value: 'filesystem-path',
120
- });
121
- }
122
- mcpConfig.customServers.forEach((server, index) => {
123
- menuItems.push({
124
- label: `${server.name} (${server.command})`,
125
- value: `custom-${index}`,
126
- });
127
- });
128
- menuItems.push({ label: 'Add Custom Server', value: 'add-custom' }, { label: 'Done (changes auto-saved)', value: 'save' }, { label: 'Back to Menu', value: 'back' });
129
- return (React.createElement(TerminalWindow, { title: "MCP Server Configuration" },
130
- React.createElement(Box, { flexDirection: "column" },
131
- React.createElement(Box, { marginBottom: 2 },
132
- React.createElement(StatusBadge, { status: "info" }),
133
- React.createElement(Text, null, "Configure Model Context Protocol servers")),
134
- React.createElement(SelectInput, { items: menuItems, onSelect: item => {
135
- if (item.value === 'filesystem') {
136
- const enableFilesystem = !mcpConfig.enableFilesystem;
137
- onSetMcpConfig({ enableFilesystem });
138
- onSaveMCPConfig();
139
- }
140
- else if (item.value === 'filesystem-path') {
141
- onSetEditingFilesystemPath(true);
142
- }
143
- else if (item.value === 'add-custom') {
144
- onSetMcpConfig({ addingCustom: true });
145
- }
146
- else if (item.value === 'save') {
147
- onSaveMCPConfig();
148
- onSetScreen('welcome');
149
- }
150
- else if (item.value === 'back') {
151
- onSetScreen('welcome');
152
- }
153
- else if (item.value.startsWith('custom-')) {
154
- const index = parseInt(item.value.replace('custom-', ''));
155
- const newCustomServers = mcpConfig.customServers.filter((_, i) => i !== index);
156
- onSetMcpConfig({ customServers: newCustomServers });
157
- onSaveMCPConfig();
158
- }
159
- } }),
160
- React.createElement(Box, { marginY: 2 },
161
- React.createElement(Text, { dimColor: true }, "Press Enter to toggle/edit servers, or select actions"),
162
- mcpConfig.enableFilesystem && (React.createElement(Text, { dimColor: true },
163
- "Filesystem path: ",
164
- mcpConfig.filesystemPath)),
165
- React.createElement(Text, { dimColor: true },
166
- "Config saved to: ",
167
- getMCPConfigPath())))));
168
- };
@@ -1,12 +0,0 @@
1
- import React from 'react';
2
- import { type Config } from '../types';
3
- import { type AppState } from '../hooks/useStableState';
4
- interface Props {
5
- state: AppState;
6
- currentConfig: Config;
7
- actions: any;
8
- stableHandlers: any;
9
- exit: () => void;
10
- }
11
- export declare const ScreenRouter: React.FC<Props>;
12
- export {};
@@ -1,22 +0,0 @@
1
- import React from 'react';
2
- import { WelcomeScreen } from './WelcomeScreen.js';
3
- import { ChatScreen } from './ChatScreen.js';
4
- import { LoadingScreen } from './LoadingScreen.js';
5
- import { SetupScreen } from './SetupScreen.js';
6
- import { MCPConfigScreen } from './MCPConfigScreen.js';
7
- export const ScreenRouter = ({ state, currentConfig, actions, stableHandlers, exit, }) => {
8
- switch (state.screen) {
9
- case 'welcome':
10
- return (React.createElement(WelcomeScreen, { config: currentConfig, onExit: exit, onInitializeAgent: stableHandlers.initializeAgent, onSetScreen: actions.setScreen }));
11
- case 'loading':
12
- return React.createElement(LoadingScreen, null);
13
- case 'setup':
14
- return (React.createElement(SetupScreen, { config: currentConfig, currentField: state.currentField, error: state.error, onUpdateConfig: stableHandlers.updateConfig, onSetCurrentField: actions.setCurrentField, onInitializeAgent: stableHandlers.initializeAgent }));
15
- case 'mcp-config':
16
- return (React.createElement(MCPConfigScreen, { mcpConfig: state.mcpConfig, editingFilesystemPath: state.editingFilesystemPath, onSetMcpConfig: actions.setMcpConfig, onSetEditingFilesystemPath: actions.setEditingFilesystemPath, onSetScreen: actions.setScreen, onSaveMCPConfig: stableHandlers.saveMCPConfig, getMCPConfigPath: stableHandlers.getMCPConfigPath }));
17
- case 'chat':
18
- return (React.createElement(ChatScreen, { config: currentConfig, messages: state.messages, input: state.input, isLoading: state.isLoading, setInput: actions.setInput, sendMessage: stableHandlers.sendMessage, showLogs: false, logs: state.logs }));
19
- default:
20
- return null;
21
- }
22
- };