@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.
Files changed (81) hide show
  1. package/README.md +29 -0
  2. package/out/auth/AuthConfig.d.ts +54 -0
  3. package/out/auth/AuthConfig.d.ts.map +1 -0
  4. package/out/auth/AuthConfig.js +70 -0
  5. package/out/auth/AuthConfig.js.map +1 -0
  6. package/out/auth/AuthService.d.ts +74 -0
  7. package/out/auth/AuthService.d.ts.map +1 -0
  8. package/out/auth/AuthService.js +275 -0
  9. package/out/auth/AuthService.js.map +1 -0
  10. package/out/auth/CallbackServer.d.ts +15 -0
  11. package/out/auth/CallbackServer.d.ts.map +1 -0
  12. package/out/auth/CallbackServer.js +277 -0
  13. package/out/auth/CallbackServer.js.map +1 -0
  14. package/out/auth/TokenCache.d.ts +81 -0
  15. package/out/auth/TokenCache.d.ts.map +1 -0
  16. package/out/auth/TokenCache.js +191 -0
  17. package/out/auth/TokenCache.js.map +1 -0
  18. package/out/auth/index.d.ts +11 -0
  19. package/out/auth/index.d.ts.map +1 -0
  20. package/out/auth/index.js +13 -0
  21. package/out/auth/index.js.map +1 -0
  22. package/out/auth/types.d.ts +75 -0
  23. package/out/auth/types.d.ts.map +1 -0
  24. package/out/auth/types.js +15 -0
  25. package/out/auth/types.js.map +1 -0
  26. package/out/cli.d.ts.map +1 -1
  27. package/out/cli.js +224 -34
  28. package/out/cli.js.map +1 -1
  29. package/out/repl/ReplModeInk.d.ts +1 -0
  30. package/out/repl/ReplModeInk.d.ts.map +1 -1
  31. package/out/repl/ReplModeInk.js +231 -22
  32. package/out/repl/ReplModeInk.js.map +1 -1
  33. package/out/secure-config/BaseDirResolver.d.ts +5 -0
  34. package/out/secure-config/BaseDirResolver.d.ts.map +1 -0
  35. package/out/secure-config/BaseDirResolver.js +20 -0
  36. package/out/secure-config/BaseDirResolver.js.map +1 -0
  37. package/out/secure-config/DeviceKeyService.d.ts +13 -0
  38. package/out/secure-config/DeviceKeyService.d.ts.map +1 -0
  39. package/out/secure-config/DeviceKeyService.js +51 -0
  40. package/out/secure-config/DeviceKeyService.js.map +1 -0
  41. package/out/secure-config/DeviceStore.d.ts +13 -0
  42. package/out/secure-config/DeviceStore.d.ts.map +1 -0
  43. package/out/secure-config/DeviceStore.js +39 -0
  44. package/out/secure-config/DeviceStore.js.map +1 -0
  45. package/out/secure-config/InstructionNormalizer.d.ts +5 -0
  46. package/out/secure-config/InstructionNormalizer.d.ts.map +1 -0
  47. package/out/secure-config/InstructionNormalizer.js +20 -0
  48. package/out/secure-config/InstructionNormalizer.js.map +1 -0
  49. package/out/secure-config/KeysetService.d.ts +15 -0
  50. package/out/secure-config/KeysetService.d.ts.map +1 -0
  51. package/out/secure-config/KeysetService.js +88 -0
  52. package/out/secure-config/KeysetService.js.map +1 -0
  53. package/out/secure-config/SCPService.d.ts +14 -0
  54. package/out/secure-config/SCPService.d.ts.map +1 -0
  55. package/out/secure-config/SCPService.js +79 -0
  56. package/out/secure-config/SCPService.js.map +1 -0
  57. package/out/secure-config/SecureConfigClient.d.ts +30 -0
  58. package/out/secure-config/SecureConfigClient.d.ts.map +1 -0
  59. package/out/secure-config/SecureConfigClient.js +81 -0
  60. package/out/secure-config/SecureConfigClient.js.map +1 -0
  61. package/out/secure-config/errors.d.ts +8 -0
  62. package/out/secure-config/errors.d.ts.map +1 -0
  63. package/out/secure-config/errors.js +20 -0
  64. package/out/secure-config/errors.js.map +1 -0
  65. package/out/secure-config/index.d.ts +11 -0
  66. package/out/secure-config/index.d.ts.map +1 -0
  67. package/out/secure-config/index.js +11 -0
  68. package/out/secure-config/index.js.map +1 -0
  69. package/out/secure-config/rootKey.d.ts +3 -0
  70. package/out/secure-config/rootKey.d.ts.map +1 -0
  71. package/out/secure-config/rootKey.js +57 -0
  72. package/out/secure-config/rootKey.js.map +1 -0
  73. package/out/secure-config/signatureUtils.d.ts +3 -0
  74. package/out/secure-config/signatureUtils.d.ts.map +1 -0
  75. package/out/secure-config/signatureUtils.js +23 -0
  76. package/out/secure-config/signatureUtils.js.map +1 -0
  77. package/out/secure-config/types.d.ts +79 -0
  78. package/out/secure-config/types.d.ts.map +1 -0
  79. package/out/secure-config/types.js +2 -0
  80. package/out/secure-config/types.js.map +1 -0
  81. package/package.json +2 -2
@@ -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 all team configurations' },
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
- 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 })] })] }), _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: "/help" }), " for available commands"] }), _jsxs(Text, { dimColor: true, children: [" Type ", _jsx(Text, { color: "green", children: "/exit" }), " to quit"] })] }));
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
- const handleTeamCommand = (args) => {
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
- appendOutput(_jsx(TeamList, {}, `team-list-${getNextKey()}`));
1450
+ await handleTeamList();
1244
1451
  break;
1245
1452
  case 'deploy':
1246
- if (subargs.length === 0) {
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