@testany/hephos 0.3.18 → 0.4.0-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/out/auth/AuthConfig.d.ts +54 -0
- package/out/auth/AuthConfig.d.ts.map +1 -0
- package/out/auth/AuthConfig.js +70 -0
- package/out/auth/AuthConfig.js.map +1 -0
- package/out/auth/AuthService.d.ts +74 -0
- package/out/auth/AuthService.d.ts.map +1 -0
- package/out/auth/AuthService.js +275 -0
- package/out/auth/AuthService.js.map +1 -0
- package/out/auth/CallbackServer.d.ts +15 -0
- package/out/auth/CallbackServer.d.ts.map +1 -0
- package/out/auth/CallbackServer.js +277 -0
- package/out/auth/CallbackServer.js.map +1 -0
- package/out/auth/TokenCache.d.ts +81 -0
- package/out/auth/TokenCache.d.ts.map +1 -0
- package/out/auth/TokenCache.js +191 -0
- package/out/auth/TokenCache.js.map +1 -0
- package/out/auth/index.d.ts +11 -0
- package/out/auth/index.d.ts.map +1 -0
- package/out/auth/index.js +13 -0
- package/out/auth/index.js.map +1 -0
- package/out/auth/types.d.ts +75 -0
- package/out/auth/types.d.ts.map +1 -0
- package/out/auth/types.js +15 -0
- package/out/auth/types.js.map +1 -0
- package/out/cli.d.ts.map +1 -1
- package/out/cli.js +224 -34
- package/out/cli.js.map +1 -1
- package/out/repl/ReplModeInk.d.ts +1 -0
- package/out/repl/ReplModeInk.d.ts.map +1 -1
- package/out/repl/ReplModeInk.js +231 -22
- package/out/repl/ReplModeInk.js.map +1 -1
- package/out/secure-config/BaseDirResolver.d.ts +5 -0
- package/out/secure-config/BaseDirResolver.d.ts.map +1 -0
- package/out/secure-config/BaseDirResolver.js +20 -0
- package/out/secure-config/BaseDirResolver.js.map +1 -0
- package/out/secure-config/DeviceKeyService.d.ts +13 -0
- package/out/secure-config/DeviceKeyService.d.ts.map +1 -0
- package/out/secure-config/DeviceKeyService.js +51 -0
- package/out/secure-config/DeviceKeyService.js.map +1 -0
- package/out/secure-config/DeviceStore.d.ts +13 -0
- package/out/secure-config/DeviceStore.d.ts.map +1 -0
- package/out/secure-config/DeviceStore.js +39 -0
- package/out/secure-config/DeviceStore.js.map +1 -0
- package/out/secure-config/InstructionNormalizer.d.ts +5 -0
- package/out/secure-config/InstructionNormalizer.d.ts.map +1 -0
- package/out/secure-config/InstructionNormalizer.js +20 -0
- package/out/secure-config/InstructionNormalizer.js.map +1 -0
- package/out/secure-config/KeysetService.d.ts +15 -0
- package/out/secure-config/KeysetService.d.ts.map +1 -0
- package/out/secure-config/KeysetService.js +88 -0
- package/out/secure-config/KeysetService.js.map +1 -0
- package/out/secure-config/SCPService.d.ts +14 -0
- package/out/secure-config/SCPService.d.ts.map +1 -0
- package/out/secure-config/SCPService.js +79 -0
- package/out/secure-config/SCPService.js.map +1 -0
- package/out/secure-config/SecureConfigClient.d.ts +30 -0
- package/out/secure-config/SecureConfigClient.d.ts.map +1 -0
- package/out/secure-config/SecureConfigClient.js +81 -0
- package/out/secure-config/SecureConfigClient.js.map +1 -0
- package/out/secure-config/errors.d.ts +8 -0
- package/out/secure-config/errors.d.ts.map +1 -0
- package/out/secure-config/errors.js +20 -0
- package/out/secure-config/errors.js.map +1 -0
- package/out/secure-config/index.d.ts +11 -0
- package/out/secure-config/index.d.ts.map +1 -0
- package/out/secure-config/index.js +11 -0
- package/out/secure-config/index.js.map +1 -0
- package/out/secure-config/rootKey.d.ts +3 -0
- package/out/secure-config/rootKey.d.ts.map +1 -0
- package/out/secure-config/rootKey.js +57 -0
- package/out/secure-config/rootKey.js.map +1 -0
- package/out/secure-config/signatureUtils.d.ts +3 -0
- package/out/secure-config/signatureUtils.d.ts.map +1 -0
- package/out/secure-config/signatureUtils.js +23 -0
- package/out/secure-config/signatureUtils.js.map +1 -0
- package/out/secure-config/types.d.ts +79 -0
- package/out/secure-config/types.d.ts.map +1 -0
- package/out/secure-config/types.js +2 -0
- package/out/secure-config/types.js.map +1 -0
- package/package.json +2 -2
package/out/repl/ReplModeInk.js
CHANGED
|
@@ -7,6 +7,7 @@ import { render, Box, Text, useInput, useApp, Static, useStdout } from 'ink';
|
|
|
7
7
|
import TextInput, { getLineInfo } from 'ink-text-input';
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import { watch } from 'fs';
|
|
10
|
+
import * as os from 'os';
|
|
10
11
|
import * as path from 'path';
|
|
11
12
|
import { fileURLToPath } from 'url';
|
|
12
13
|
import { detectAllTools, CORE_VERSION } from '@testany/agent-chatter-core';
|
|
@@ -27,6 +28,8 @@ import { QueueDisplay } from './components/QueueDisplay.js';
|
|
|
27
28
|
import { TipsBar } from './components/TipsBar.js';
|
|
28
29
|
import { HistoryOverlay } from './components/HistoryOverlay.js';
|
|
29
30
|
import { useHistory } from './hooks/useHistory.js';
|
|
31
|
+
import { AuthService, isValidRegion, isValidEnvironment, AUTH_CONFIG, tokenCache, AuthError } from '../auth/index.js';
|
|
32
|
+
import { SecureConfigClient, DeviceKeyService, SecureConfigError, KeysetService, SCPService, InstructionNormalizer, BaseDirResolver, resolveRootPublicKeyPem } from '../secure-config/index.js';
|
|
30
33
|
// Read version from package.json
|
|
31
34
|
const __filename = fileURLToPath(import.meta.url);
|
|
32
35
|
const __dirname = path.dirname(__filename);
|
|
@@ -38,15 +41,22 @@ const commands = [
|
|
|
38
41
|
{ name: '/status', desc: 'Check installed AI CLI tools' },
|
|
39
42
|
{ name: '/agents', desc: 'Manage registered AI agents' },
|
|
40
43
|
{ name: '/team', desc: 'Manage team configurations' },
|
|
44
|
+
{ name: '/login', desc: 'Login to HephOS cloud' },
|
|
41
45
|
{ name: '/tips', desc: 'Toggle syntax tips in conversation mode' },
|
|
42
46
|
{ name: '/clear', desc: 'Clear the screen' },
|
|
43
47
|
{ name: '/exit', desc: 'Exit the application' },
|
|
44
48
|
{ name: '/quit', desc: 'Same as /exit' },
|
|
45
49
|
];
|
|
50
|
+
const loginCommands = [
|
|
51
|
+
{ name: '/login cn', desc: 'Login to China Region' },
|
|
52
|
+
{ name: '/login us', desc: 'Login to International Region' },
|
|
53
|
+
{ name: '/login status', desc: 'Show authentication status' },
|
|
54
|
+
{ name: '/login logout', desc: 'Logout from current region' },
|
|
55
|
+
];
|
|
46
56
|
const teamCommands = [
|
|
47
57
|
{ name: '/team create', desc: 'Create a new team configuration' },
|
|
48
|
-
{ name: '/team list', desc: 'List
|
|
49
|
-
{ name: '/team deploy', desc: 'Deploy and load a team configuration' },
|
|
58
|
+
{ name: '/team list', desc: 'List cloud and local team configurations' },
|
|
59
|
+
{ name: '/team deploy', desc: 'Deploy and load a team configuration (file or team_id)' },
|
|
50
60
|
{ name: '/team edit', desc: 'Edit an existing team configuration' },
|
|
51
61
|
{ name: '/team delete', desc: 'Delete a team configuration' },
|
|
52
62
|
];
|
|
@@ -60,7 +70,11 @@ const agentsCommands = [
|
|
|
60
70
|
];
|
|
61
71
|
// 欢迎界面组件
|
|
62
72
|
function WelcomeScreen() {
|
|
63
|
-
|
|
73
|
+
// Check login status
|
|
74
|
+
const activeRegion = tokenCache.getActiveRegion();
|
|
75
|
+
const userInfo = activeRegion ? tokenCache.getUserInfo(activeRegion) : null;
|
|
76
|
+
const isLoggedIn = activeRegion && tokenCache.isValid(activeRegion);
|
|
77
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 0, flexDirection: "column", children: [_jsx(Logo, {}), _jsx(Text, { dimColor: true, children: "Multi-AI Conversation Orchestrator" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " CLI version " }), _jsx(Text, { color: "white", children: VERSION })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " Core version " }), _jsx(Text, { color: "white", children: CORE_VERSION })] }), isLoggedIn && userInfo && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " Logged in " }), _jsxs(Text, { color: "green", children: ["HephOS ", activeRegion.toUpperCase()] }), _jsx(Text, { dimColor: true, children: " as " }), _jsx(Text, { color: "white", children: userInfo.email || userInfo.name || 'unknown' })] }))] }), _jsxs(Text, { dimColor: true, children: [" built by ", _jsx(Text, { color: "cyan", children: "TestAny.io" })] }), _jsxs(Text, { dimColor: true, children: [" Type ", _jsx(Text, { color: "green", children: "/login" }), " to login"] }), _jsxs(Text, { dimColor: true, children: [" Type ", _jsx(Text, { color: "green", children: "/help" }), " for available commands"] }), _jsxs(Text, { dimColor: true, children: [" Type ", _jsx(Text, { color: "green", children: "/exit" }), " to quit"] })] }));
|
|
64
78
|
}
|
|
65
79
|
// 更新通知组件
|
|
66
80
|
function UpdateNotification({ versionInfo }) {
|
|
@@ -134,7 +148,7 @@ function HelpMessage({ mode }) {
|
|
|
134
148
|
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Conversation Mode Help" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Available Commands:" }), conversationModeCommands.map(cmd => (_jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: cmd.name.padEnd(18) }), _jsx(Text, { dimColor: true, children: cmd.desc })] }, cmd.name)))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Message Markers:" }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: '[NEXT:name]'.padEnd(18) }), _jsx(Text, { dimColor: true, children: "Send message to specific team member" })] }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: '[NEXT:name!P1]'.padEnd(18) }), _jsx(Text, { dimColor: true, children: "Mark as urgent - gets handled first" })] }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: '[NEXT:name!P3]'.padEnd(18) }), _jsx(Text, { dimColor: true, children: "Mark as low priority - can wait" })] }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: '[FROM:name]'.padEnd(18) }), _jsx(Text, { dimColor: true, children: "Identify yourself (needed when multiple humans)" })] }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: '[TEAM_TASK:desc]'.padEnd(18) }), _jsx(Text, { dimColor: true, children: "Set a shared goal for the whole team" })] }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: '[DROP:name]'.padEnd(18) }), _jsx(Text, { dimColor: true, children: "Cancel pending tasks for someone" })] })] })] }));
|
|
135
149
|
}
|
|
136
150
|
// Normal mode help
|
|
137
|
-
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Normal Mode Help" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Available Commands:" }), commands.map(cmd => (_jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: cmd.name.padEnd(18) }), _jsx(Text, { dimColor: true, children: cmd.desc })] }, cmd.name)))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Quick Start:" }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["1. Use ", _jsx(Text, { color: "green", children: "/team list" }), " to see available teams"] }), _jsxs(Text, { dimColor: true, children: ["2. Use ", _jsx(Text, { color: "green", children: "/team deploy <filename>" }), " to start a conversation"] })] })] })] }));
|
|
151
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Normal Mode Help" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Available Commands:" }), commands.map(cmd => (_jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "green", children: cmd.name.padEnd(18) }), _jsx(Text, { dimColor: true, children: cmd.desc })] }, cmd.name)))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Quick Start:" }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["1. Use ", _jsx(Text, { color: "green", children: "/team list" }), " to see available teams"] }), _jsxs(Text, { dimColor: true, children: ["2. Use ", _jsx(Text, { color: "green", children: "/team deploy <filename|team_id>" }), " to start a conversation"] })] })] })] }));
|
|
138
152
|
}
|
|
139
153
|
/**
|
|
140
154
|
* Renders the active todo list with in-place updates.
|
|
@@ -163,7 +177,13 @@ function TeamList() {
|
|
|
163
177
|
if (configs.length === 0) {
|
|
164
178
|
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: "yellow", children: "No team configurations found" }), _jsx(Text, { dimColor: true, children: "Use /team create to create a team configuration" })] }));
|
|
165
179
|
}
|
|
166
|
-
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Available Teams:" }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: configs.map((config, idx) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsxs(Text, { color: "cyan", bold: true, children: ["[", idx + 1, "]"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "green", children: config.displayName })] }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["File: ", config.filename] }) }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["Members: ", config.memberCount, " (", config.aiCount, " AI, ", config.humanCount, " Human)"] }) })] }, config.filename))) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Type " }), _jsx(Text, { color: "green", children: "/team deploy <filename>" }), _jsx(Text, { dimColor: true, children: " to deploy a team" })] })] }));
|
|
180
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Available Teams:" }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: configs.map((config, idx) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsxs(Text, { color: "cyan", bold: true, children: ["[", idx + 1, "]"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "green", children: config.displayName })] }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["File: ", config.filename] }) }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["Members: ", config.memberCount, " (", config.aiCount, " AI, ", config.humanCount, " Human)"] }) })] }, config.filename))) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Type " }), _jsx(Text, { color: "green", children: "/team deploy <filename|team_id>" }), _jsx(Text, { dimColor: true, children: " to deploy a team" })] })] }));
|
|
181
|
+
}
|
|
182
|
+
function CloudTeamList({ teams, region, env }) {
|
|
183
|
+
if (teams.length === 0) {
|
|
184
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { color: "yellow", children: ["No cloud teams found for ", region.toUpperCase(), " ", env] }), _jsx(Text, { dimColor: true, children: "Check your HephOS web account or switch environment." })] }));
|
|
185
|
+
}
|
|
186
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { bold: true, children: ["Cloud Teams (", region.toUpperCase(), " ", env, ")"] }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: teams.map((team, idx) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsxs(Text, { color: "cyan", bold: true, children: ["[", idx + 1, "]"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "green", children: team.display_name || team.name || team.team_id })] }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["Team ID: ", team.team_id] }) }), team.status && (_jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["Status: ", team.status] }) }))] }, team.team_id))) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Use " }), _jsx(Text, { color: "green", children: "/team deploy <team_id>" }), _jsx(Text, { dimColor: true, children: " (REPL) or " }), _jsx(Text, { color: "green", children: "hephos team deploy --team <team_id>" }), _jsx(Text, { dimColor: true, children: " (CLI)" })] })] }));
|
|
167
187
|
}
|
|
168
188
|
// Team menu help component
|
|
169
189
|
function TeamMenuHelp() {
|
|
@@ -213,7 +233,7 @@ function SelectView({ title, options, selectedIndex, multiSelect, selectedItems
|
|
|
213
233
|
return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? 'green' : 'gray', bold: isSelected, children: [isSelected ? '▶ ' : ' ', multiSelect ? (isChecked ? '☑' : '☐') : '', ' ', option] }) }, idx));
|
|
214
234
|
}) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Use " }), _jsx(Text, { color: "yellow", children: "\u2191\u2193" }), _jsx(Text, { dimColor: true, children: " to navigate, " }), multiSelect && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", children: "Space" }), _jsx(Text, { dimColor: true, children: " to toggle, " })] })), _jsx(Text, { color: "yellow", children: "Enter" }), _jsx(Text, { dimColor: true, children: " to confirm" })] })] }));
|
|
215
235
|
}
|
|
216
|
-
function App({ registryPath, debug = false, proxyUrl }) {
|
|
236
|
+
function App({ registryPath, debug = false, proxyUrl, autoDeployConfigPath }) {
|
|
217
237
|
const { stdout } = useStdout();
|
|
218
238
|
const terminalWidth = stdout?.columns || 80;
|
|
219
239
|
const [input, setInput] = useState('');
|
|
@@ -233,6 +253,7 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
233
253
|
const [isExiting, setIsExiting] = useState(false);
|
|
234
254
|
const [queueState, setQueueState] = useState(null);
|
|
235
255
|
const [showTips, setShowTips] = useState(true); // Tips bar visibility (default: on)
|
|
256
|
+
const autoDeployOnceRef = useRef(false);
|
|
236
257
|
// Command history management
|
|
237
258
|
const history = useHistory();
|
|
238
259
|
// Track previous queue size to detect DROP-triggered clears
|
|
@@ -1160,11 +1181,14 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
1160
1181
|
appendOutput(_jsx(StatusDisplay, { tools: tools }, `status-${getNextKey()}`));
|
|
1161
1182
|
break;
|
|
1162
1183
|
case '/team':
|
|
1163
|
-
handleTeamCommand(args);
|
|
1184
|
+
await handleTeamCommand(args);
|
|
1164
1185
|
break;
|
|
1165
1186
|
case '/agents':
|
|
1166
1187
|
handleAgentsCommand(args);
|
|
1167
1188
|
break;
|
|
1189
|
+
case '/login':
|
|
1190
|
+
await handleLoginCommand(args);
|
|
1191
|
+
break;
|
|
1168
1192
|
case '/tips':
|
|
1169
1193
|
if (args[0] === 'off') {
|
|
1170
1194
|
setShowTips(false);
|
|
@@ -1220,7 +1244,7 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
1220
1244
|
default:
|
|
1221
1245
|
// Check if this looks like a conversation message (not starting with /)
|
|
1222
1246
|
if (!command.startsWith('/')) {
|
|
1223
|
-
appendOutput(_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: "yellow", children: "\u26A0 You are not in conversation mode." }), _jsx(Text, { dimColor: true, children: "To start a conversation:" }), _jsxs(Text, { dimColor: true, children: [" 1. Use ", _jsx(Text, { color: "green", children: "/team list" }), " to see available teams"] }), _jsxs(Text, { dimColor: true, children: [" 2. Use ", _jsx(Text, { color: "green", children: "/team deploy <filename>" }), " to deploy a team"] }), _jsx(Text, { dimColor: true, children: " 3. Then type your message to start talking" })] }, `not-deployed-${getNextKey()}`));
|
|
1247
|
+
appendOutput(_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: "yellow", children: "\u26A0 You are not in conversation mode." }), _jsx(Text, { dimColor: true, children: "To start a conversation:" }), _jsxs(Text, { dimColor: true, children: [" 1. Use ", _jsx(Text, { color: "green", children: "/team list" }), " to see available teams"] }), _jsxs(Text, { dimColor: true, children: [" 2. Use ", _jsx(Text, { color: "green", children: "/team deploy <filename|team_id>" }), " to deploy a team"] }), _jsx(Text, { dimColor: true, children: " 3. Then type your message to start talking" })] }, `not-deployed-${getNextKey()}`));
|
|
1224
1248
|
}
|
|
1225
1249
|
else {
|
|
1226
1250
|
appendOutput(_jsxs(Text, { color: "yellow", children: ["Unknown command: ", command] }, `unknown-${getNextKey()}`));
|
|
@@ -1228,7 +1252,190 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
1228
1252
|
}
|
|
1229
1253
|
}
|
|
1230
1254
|
};
|
|
1231
|
-
|
|
1255
|
+
// Handle /login command
|
|
1256
|
+
const handleLoginCommand = async (args) => {
|
|
1257
|
+
if (args.length === 0) {
|
|
1258
|
+
// Show login help/region selection
|
|
1259
|
+
appendOutput(_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Login to HephOS Cloud" }), _jsx(Text, { dimColor: true, children: "Usage: /login <region> [--env <prod|staging>] | /login status | /login logout" }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Available regions:" }), _jsxs(Text, { children: [" cn - ", AUTH_CONFIG.cn.displayName] }), _jsxs(Text, { children: [" us - ", AUTH_CONFIG.us.displayName] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Available environments:" }), _jsx(Text, { children: " prod - Production (default)" }), _jsx(Text, { children: " staging - Staging/UAT" }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Commands:" }), _jsx(Text, { children: " /login cn - Login to CN region (prod)" }), _jsx(Text, { children: " /login us --env staging - Login to US staging" }), _jsx(Text, { children: " /login status - Show authentication status" }), _jsx(Text, { children: " /login logout - Logout from current region" })] }, `login-help-${getNextKey()}`));
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
const subcommand = args[0].toLowerCase();
|
|
1263
|
+
if (subcommand === 'status') {
|
|
1264
|
+
// Show auth status
|
|
1265
|
+
const activeRegion = tokenCache.getActiveRegion();
|
|
1266
|
+
const activeEnv = tokenCache.getActiveEnv();
|
|
1267
|
+
appendOutput(_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "HephOS Authentication Status" }), _jsx(Text, { children: " " }), _jsxs(Text, { dimColor: true, children: ["Environment: ", activeEnv] }), _jsx(Text, { children: " " }), ['cn', 'us'].map(region => {
|
|
1268
|
+
const config = AUTH_CONFIG[region];
|
|
1269
|
+
const isValid = tokenCache.isValid(region);
|
|
1270
|
+
const userInfo = tokenCache.getUserInfo(region);
|
|
1271
|
+
const isActive = activeRegion === region;
|
|
1272
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [config.displayName, isActive && _jsx(Text, { color: "cyan", children: " (active)" })] }), _jsxs(Text, { children: [' Status: ', isValid
|
|
1273
|
+
? _jsx(Text, { color: "green", children: "\u2713 Logged in" })
|
|
1274
|
+
: _jsx(Text, { dimColor: true, children: "\u2717 Not logged in" })] }), userInfo && (_jsxs(_Fragment, { children: [_jsxs(Text, { dimColor: true, children: [" Email: ", userInfo.email || 'N/A'] }), _jsxs(Text, { dimColor: true, children: [" User ID: ", userInfo.sub] })] }))] }, region));
|
|
1275
|
+
}), _jsxs(Text, { dimColor: true, children: ["Token cache: ", tokenCache.getCachePath()] })] }, `auth-status-${getNextKey()}`));
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
if (subcommand === 'logout') {
|
|
1279
|
+
const region = args[1]?.toLowerCase();
|
|
1280
|
+
const targetRegion = region && isValidRegion(region) ? region : tokenCache.getActiveRegion();
|
|
1281
|
+
if (!targetRegion) {
|
|
1282
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "No active session to logout from." }, `logout-none-${getNextKey()}`));
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
const config = AUTH_CONFIG[targetRegion];
|
|
1286
|
+
appendOutput(_jsxs(Text, { dimColor: true, children: ["Logging out from ", config.displayName, "..."] }, `logout-msg-${getNextKey()}`));
|
|
1287
|
+
try {
|
|
1288
|
+
const authService = new AuthService(targetRegion, tokenCache.getActiveEnv());
|
|
1289
|
+
await authService.logout();
|
|
1290
|
+
appendOutput(_jsx(Text, { color: "green", children: "\u2713 Logged out successfully." }, `logout-ok-${getNextKey()}`));
|
|
1291
|
+
}
|
|
1292
|
+
catch (err) {
|
|
1293
|
+
tokenCache.clear(targetRegion);
|
|
1294
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "Local tokens cleared." }, `logout-warn-${getNextKey()}`));
|
|
1295
|
+
}
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
// Login to a region
|
|
1299
|
+
if (!isValidRegion(subcommand)) {
|
|
1300
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["Invalid region \"", subcommand, "\". Use 'cn' or 'us'."] }, `login-invalid-${getNextKey()}`));
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
const region = subcommand;
|
|
1304
|
+
let env = tokenCache.getActiveEnv();
|
|
1305
|
+
const envFlagIndex = args.findIndex(arg => arg === '--env' || arg === '-e');
|
|
1306
|
+
if (envFlagIndex >= 0) {
|
|
1307
|
+
const envValue = args[envFlagIndex + 1]?.toLowerCase();
|
|
1308
|
+
if (!envValue || !isValidEnvironment(envValue)) {
|
|
1309
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["Invalid environment \"", envValue || '', "\". Use 'prod' or 'staging'."] }, `login-env-invalid-${getNextKey()}`));
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
env = envValue;
|
|
1313
|
+
}
|
|
1314
|
+
else if (args[1] && isValidEnvironment(args[1].toLowerCase())) {
|
|
1315
|
+
env = args[1].toLowerCase();
|
|
1316
|
+
}
|
|
1317
|
+
const config = AUTH_CONFIG[region];
|
|
1318
|
+
appendOutput(_jsxs(Text, { color: "cyan", children: ["\uD83D\uDD10 Opening browser for HephOS login (", config.displayName, ", ", env, ")..."] }, `login-start-${getNextKey()}`));
|
|
1319
|
+
appendOutput(_jsx(Text, { dimColor: true, children: " Complete login in your browser to continue." }, `login-hint-${getNextKey()}`));
|
|
1320
|
+
try {
|
|
1321
|
+
const authService = new AuthService(region, env);
|
|
1322
|
+
const result = await authService.login();
|
|
1323
|
+
appendOutput(_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "green", children: ["\u2713 Login successful! (", env, ")"] }), _jsxs(Text, { bold: true, children: [" Welcome, ", result.userInfo.email || result.userInfo.name || result.userInfo.sub] }), _jsxs(Text, { dimColor: true, children: [" Token cached at: ", tokenCache.getCachePath()] })] }, `login-success-${getNextKey()}`));
|
|
1324
|
+
}
|
|
1325
|
+
catch (err) {
|
|
1326
|
+
if (err instanceof AuthError) {
|
|
1327
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["\u2717 Login failed: ", err.message] }, `login-error-${getNextKey()}`));
|
|
1328
|
+
}
|
|
1329
|
+
else {
|
|
1330
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["\u2717 Login failed: ", err instanceof Error ? err.message : String(err)] }, `login-error-${getNextKey()}`));
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
const handleTeamList = async () => {
|
|
1335
|
+
const activeRegion = tokenCache.getActiveRegion();
|
|
1336
|
+
const env = tokenCache.getActiveEnv();
|
|
1337
|
+
if (!activeRegion) {
|
|
1338
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "Not logged in. Use /login <region> --env <prod|staging> to list cloud teams." }, `team-list-login-${getNextKey()}`));
|
|
1339
|
+
appendOutput(_jsx(TeamList, {}, `team-list-local-${getNextKey()}`));
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
appendOutput(_jsxs(Text, { dimColor: true, children: ["Fetching cloud teams (", activeRegion.toUpperCase(), " ", env, ")..."] }, `team-list-fetch-${getNextKey()}`));
|
|
1343
|
+
try {
|
|
1344
|
+
const authService = new AuthService(activeRegion, env);
|
|
1345
|
+
const accessToken = await authService.getValidAccessToken();
|
|
1346
|
+
if (!accessToken) {
|
|
1347
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "Access token expired. Please /login again." }, `team-list-expired-${getNextKey()}`));
|
|
1348
|
+
}
|
|
1349
|
+
else {
|
|
1350
|
+
const deviceKeyService = new DeviceKeyService();
|
|
1351
|
+
const deviceKey = await deviceKeyService.getOrCreateDeviceKey();
|
|
1352
|
+
const client = new SecureConfigClient({
|
|
1353
|
+
region: activeRegion,
|
|
1354
|
+
environment: env,
|
|
1355
|
+
accessToken,
|
|
1356
|
+
deviceId: deviceKey.deviceId,
|
|
1357
|
+
clientType: 'cli',
|
|
1358
|
+
clientVersion: VERSION
|
|
1359
|
+
});
|
|
1360
|
+
const list = await client.listTeams(50);
|
|
1361
|
+
appendOutput(_jsx(CloudTeamList, { teams: list.teams, region: activeRegion, env: env }, `team-list-cloud-${getNextKey()}`));
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
catch (err) {
|
|
1365
|
+
const message = err instanceof SecureConfigError
|
|
1366
|
+
? `${err.code}: ${err.message}`
|
|
1367
|
+
: err instanceof Error ? err.message : String(err);
|
|
1368
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["Failed to fetch cloud teams: ", message] }, `team-list-error-${getNextKey()}`));
|
|
1369
|
+
}
|
|
1370
|
+
appendOutput(_jsx(TeamList, {}, `team-list-local-${getNextKey()}`));
|
|
1371
|
+
};
|
|
1372
|
+
const handleTeamDeploy = async (target) => {
|
|
1373
|
+
if (!target) {
|
|
1374
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "Usage: /team deploy <filename|team_id>" }, `team-deploy-usage-${getNextKey()}`));
|
|
1375
|
+
appendOutput(_jsx(Text, { dimColor: true, children: "Use /team list to see available configurations" }, `team-deploy-hint-${getNextKey()}`));
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
const resolution = resolveTeamConfigPath(target);
|
|
1379
|
+
if (resolution.exists) {
|
|
1380
|
+
const config = loadConfig(target);
|
|
1381
|
+
if (config) {
|
|
1382
|
+
checkAndPromptRestore(config);
|
|
1383
|
+
}
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
const activeRegion = tokenCache.getActiveRegion();
|
|
1387
|
+
const env = tokenCache.getActiveEnv();
|
|
1388
|
+
if (!activeRegion) {
|
|
1389
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "Not logged in. Use /login <region> --env <prod|staging> to deploy cloud teams." }, `team-deploy-login-${getNextKey()}`));
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
appendOutput(_jsxs(Text, { dimColor: true, children: ["Fetching secure config for ", target, " (", activeRegion.toUpperCase(), " ", env, ")..."] }, `team-deploy-fetch-${getNextKey()}`));
|
|
1393
|
+
try {
|
|
1394
|
+
const authService = new AuthService(activeRegion, env);
|
|
1395
|
+
const accessToken = await authService.getValidAccessToken();
|
|
1396
|
+
if (!accessToken) {
|
|
1397
|
+
appendOutput(_jsx(Text, { color: "yellow", children: "Access token expired. Please /login again." }, `team-deploy-expired-${getNextKey()}`));
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const deviceKeyService = new DeviceKeyService();
|
|
1401
|
+
const deviceKey = await deviceKeyService.getOrCreateDeviceKey();
|
|
1402
|
+
const client = new SecureConfigClient({
|
|
1403
|
+
region: activeRegion,
|
|
1404
|
+
environment: env,
|
|
1405
|
+
accessToken,
|
|
1406
|
+
deviceId: deviceKey.deviceId,
|
|
1407
|
+
clientType: 'cli',
|
|
1408
|
+
clientVersion: VERSION
|
|
1409
|
+
});
|
|
1410
|
+
await client.registerDevice({
|
|
1411
|
+
device_id: deviceKey.deviceId,
|
|
1412
|
+
public_key_pem: deviceKey.publicKeyPem,
|
|
1413
|
+
device_name: os.hostname()
|
|
1414
|
+
});
|
|
1415
|
+
const keysetService = new KeysetService(client, activeRegion, resolveRootPublicKeyPem(activeRegion, env));
|
|
1416
|
+
const scpService = new SCPService(deviceKeyService, keysetService);
|
|
1417
|
+
const scp = await client.fetchSCP(target);
|
|
1418
|
+
const teamConfig = await scpService.decryptSCP(scp, () => client.fetchSCP(target));
|
|
1419
|
+
InstructionNormalizer.normalize(teamConfig);
|
|
1420
|
+
BaseDirResolver.fill(teamConfig, process.cwd());
|
|
1421
|
+
ensureTeamConfigDir();
|
|
1422
|
+
const filename = `team-${target}-config.json`;
|
|
1423
|
+
const configPath = path.join(getTeamConfigDir(), filename);
|
|
1424
|
+
fs.writeFileSync(configPath, JSON.stringify(teamConfig, null, 2));
|
|
1425
|
+
appendOutput(_jsxs(Text, { color: "green", children: ["\u2713 Secure config fetched and saved: ", filename] }, `team-deploy-success-${getNextKey()}`));
|
|
1426
|
+
const config = loadConfig(filename);
|
|
1427
|
+
if (config) {
|
|
1428
|
+
checkAndPromptRestore(config);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
catch (err) {
|
|
1432
|
+
const message = err instanceof SecureConfigError
|
|
1433
|
+
? `${err.code}: ${err.message}`
|
|
1434
|
+
: err instanceof Error ? err.message : String(err);
|
|
1435
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["Failed to deploy team ", target, ": ", message] }, `team-deploy-error-${getNextKey()}`));
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
const handleTeamCommand = async (args) => {
|
|
1232
1439
|
if (args.length === 0) {
|
|
1233
1440
|
appendOutput(_jsx(TeamMenuHelp, {}, `team-help-${getNextKey()}`));
|
|
1234
1441
|
return;
|
|
@@ -1240,20 +1447,10 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
1240
1447
|
startTeamCreationWizard();
|
|
1241
1448
|
break;
|
|
1242
1449
|
case 'list':
|
|
1243
|
-
|
|
1450
|
+
await handleTeamList();
|
|
1244
1451
|
break;
|
|
1245
1452
|
case 'deploy':
|
|
1246
|
-
|
|
1247
|
-
appendOutput(_jsx(Text, { color: "yellow", children: "Usage: /team deploy <filename>" }, `team-deploy-usage-${getNextKey()}`));
|
|
1248
|
-
appendOutput(_jsx(Text, { dimColor: true, children: "Use /team list to see available configurations" }, `team-deploy-hint-${getNextKey()}`));
|
|
1249
|
-
}
|
|
1250
|
-
else {
|
|
1251
|
-
const config = loadConfig(subargs[0]);
|
|
1252
|
-
if (config) {
|
|
1253
|
-
// Check for existing session and prompt for restore
|
|
1254
|
-
checkAndPromptRestore(config);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1453
|
+
await handleTeamDeploy(subargs[0]);
|
|
1257
1454
|
break;
|
|
1258
1455
|
case 'edit':
|
|
1259
1456
|
if (subargs.length === 0) {
|
|
@@ -1588,6 +1785,18 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
1588
1785
|
return null;
|
|
1589
1786
|
}
|
|
1590
1787
|
};
|
|
1788
|
+
useEffect(() => {
|
|
1789
|
+
if (!autoDeployConfigPath || autoDeployOnceRef.current)
|
|
1790
|
+
return;
|
|
1791
|
+
autoDeployOnceRef.current = true;
|
|
1792
|
+
const config = loadConfig(autoDeployConfigPath);
|
|
1793
|
+
if (config) {
|
|
1794
|
+
checkAndPromptRestore(config);
|
|
1795
|
+
}
|
|
1796
|
+
else {
|
|
1797
|
+
appendOutput(_jsxs(Text, { color: "red", children: ["\u2717 Failed to load config for auto deploy: ", autoDeployConfigPath] }, `auto-deploy-fail-${getNextKey()}`));
|
|
1798
|
+
}
|
|
1799
|
+
}, [autoDeployConfigPath]);
|
|
1591
1800
|
const initializeAndDeployTeam = async (config) => {
|
|
1592
1801
|
try {
|
|
1593
1802
|
// Reset queue state tracking to avoid false "Queue cleared" on new session
|
|
@@ -1901,7 +2110,7 @@ function App({ registryPath, debug = false, proxyUrl }) {
|
|
|
1901
2110
|
}, onSubmit: handleInputSubmit, onCursorChange: setCursorOffset, placeholder: " " })] }), _jsx(Text, { color: mode === 'conversation' ? 'green' : 'cyan', dimColor: true, children: '─'.repeat(terminalWidth - 4) })] })), !isExiting && (mode === 'normal' || mode === 'conversation') && (history.isActive || history.searchMode) && (_jsx(HistoryOverlay, { visible: true, entries: history.entries, currentIndex: history.currentIndex, activeMode: history.activeMode, searchMode: history.searchMode, searchQuery: history.searchQuery, terminalWidth: terminalWidth })), !isExiting && mode === 'normal' && !history.isActive && !history.searchMode && _jsx(CommandHints, { input: input, selectedIndex: selectedIndex }), !isExiting && mode === 'conversation' && !history.isActive && !history.searchMode && (_jsx(TipsBar, { visible: showTips, terminalWidth: terminalWidth }))] }));
|
|
1902
2111
|
}
|
|
1903
2112
|
export function startReplInk(registryPath, options = {}) {
|
|
1904
|
-
render(_jsx(App, { registryPath: registryPath, debug: options.debug, proxyUrl: options.proxyUrl }), {
|
|
2113
|
+
render(_jsx(App, { registryPath: registryPath, debug: options.debug, proxyUrl: options.proxyUrl, autoDeployConfigPath: options.autoDeployConfigPath }), {
|
|
1905
2114
|
// Don't use alternateBuffer - it prevents scrolling for long agent outputs
|
|
1906
2115
|
// Trade-off: long input lines may cause duplicate prompts, but scrolling works
|
|
1907
2116
|
incrementalRendering: true
|