@ai-support-agent/cli 0.0.1
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/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/dist/agent-runner.d.ts +21 -0
- package/dist/agent-runner.d.ts.map +1 -0
- package/dist/agent-runner.js +251 -0
- package/dist/agent-runner.js.map +1 -0
- package/dist/api-client.d.ts +14 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +112 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth-server.d.ts +12 -0
- package/dist/auth-server.d.ts.map +1 -0
- package/dist/auth-server.js +151 -0
- package/dist/auth-server.js.map +1 -0
- package/dist/command-executor.d.ts +3 -0
- package/dist/command-executor.d.ts.map +1 -0
- package/dist/command-executor.js +306 -0
- package/dist/command-executor.js.map +1 -0
- package/dist/config-manager.d.ts +18 -0
- package/dist/config-manager.d.ts.map +1 -0
- package/dist/config-manager.js +175 -0
- package/dist/config-manager.js.map +1 -0
- package/dist/constants.d.ts +30 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +50 -0
- package/dist/constants.js.map +1 -0
- package/dist/i18n.d.ts +3 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +109 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +214 -0
- package/dist/index.js.map +1 -0
- package/dist/locales/en.json +78 -0
- package/dist/locales/ja.json +78 -0
- package/dist/locales/locales/en.json +78 -0
- package/dist/locales/locales/ja.json +78 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +41 -0
- package/dist/logger.js.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +32 -0
- package/dist/utils.js.map +1 -0
- package/package.json +51 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.0.1] - 2026-02-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial public release
|
|
12
|
+
- Multi-project support with `login`, `add-project`, `remove-project` commands
|
|
13
|
+
- Browser-based OAuth authentication
|
|
14
|
+
- Agent heartbeat and command polling
|
|
15
|
+
- Command execution (shell, file read/write/list, process management)
|
|
16
|
+
- i18n support (English default, Japanese locale)
|
|
17
|
+
- Environment variable support (`AI_SUPPORT_AGENT_API_URL`, `AI_SUPPORT_AGENT_TOKEN`)
|
|
18
|
+
- Configuration management with `~/.ai-support-agent/config.json`
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 AI Support Agent Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# AI Support Agent CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ai-support-agent/cli)
|
|
4
|
+
[](https://github.com/mbc-net/ai-support-agent-client/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
Multi-tenant AI support agent CLI that connects to your AI Support Agent server. It runs as a background agent on your machine, receiving and executing commands from the server while reporting results back in real time.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Multi-project support** - Manage multiple projects under different tenants from a single CLI
|
|
11
|
+
- **Browser-based OAuth authentication** - Secure login via Cognito with automatic browser redirect
|
|
12
|
+
- **Remote command execution** - Execute shell commands, read/write files, and manage processes
|
|
13
|
+
- **Heartbeat monitoring** - Automatic health reporting to the server
|
|
14
|
+
- **i18n support** - English (default) and Japanese locales with OS locale auto-detection
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install globally
|
|
20
|
+
npm install -g @ai-support-agent/cli
|
|
21
|
+
|
|
22
|
+
# Login via browser OAuth
|
|
23
|
+
ai-support-agent login --url https://your-web-ui.example.com
|
|
24
|
+
|
|
25
|
+
# Start the agent
|
|
26
|
+
ai-support-agent start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
| Command | Description |
|
|
32
|
+
|---------|-------------|
|
|
33
|
+
| `start` | Start the agent and begin polling for commands |
|
|
34
|
+
| `login` | Authenticate with the server via browser-based OAuth |
|
|
35
|
+
| `add-project` | Add a project to the agent configuration |
|
|
36
|
+
| `remove-project` | Remove a project from the agent configuration |
|
|
37
|
+
| `configure` | Update agent configuration interactively |
|
|
38
|
+
| `set-language` | Set the display language (`en` or `ja`) |
|
|
39
|
+
| `status` | Show current agent status and configuration |
|
|
40
|
+
|
|
41
|
+
### Start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Start with default settings
|
|
45
|
+
ai-support-agent start
|
|
46
|
+
|
|
47
|
+
# Start with verbose logging
|
|
48
|
+
ai-support-agent start --verbose
|
|
49
|
+
|
|
50
|
+
# Start with a specific project
|
|
51
|
+
ai-support-agent start --project my_project
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Login
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Login via browser OAuth
|
|
58
|
+
ai-support-agent login --url https://your-web-ui.example.com
|
|
59
|
+
|
|
60
|
+
# Login with explicit API URL
|
|
61
|
+
ai-support-agent login --url https://your-web-ui.example.com --api-url https://api.example.com
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Project Management
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Add another project via browser OAuth
|
|
68
|
+
ai-support-agent add-project --url https://your-web-ui.example.com
|
|
69
|
+
|
|
70
|
+
# Remove a project by code
|
|
71
|
+
ai-support-agent remove-project my_project
|
|
72
|
+
|
|
73
|
+
# Manual token setup (backward compatible)
|
|
74
|
+
ai-support-agent configure --token <token> --api-url <url> --project-code my_project
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration File
|
|
78
|
+
|
|
79
|
+
The agent stores its configuration at `~/.ai-support-agent/config.json`:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"agentId": "hostname-a1b2",
|
|
84
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
85
|
+
"lastConnected": "2025-01-01T12:00:00.000Z",
|
|
86
|
+
"language": "en",
|
|
87
|
+
"projects": [
|
|
88
|
+
{
|
|
89
|
+
"projectCode": "my_project",
|
|
90
|
+
"token": "agt_...",
|
|
91
|
+
"apiUrl": "https://api.example.com"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Field | Description |
|
|
98
|
+
|-------|-------------|
|
|
99
|
+
| `agentId` | Auto-generated unique agent identifier (hostname + random hex) |
|
|
100
|
+
| `createdAt` | Timestamp when the config was first created |
|
|
101
|
+
| `lastConnected` | Timestamp of last successful connection |
|
|
102
|
+
| `language` | Display language (`en` or `ja`) |
|
|
103
|
+
| `projects` | Array of registered projects with `projectCode`, `token`, and `apiUrl` |
|
|
104
|
+
|
|
105
|
+
## Environment Variables
|
|
106
|
+
|
|
107
|
+
| Variable | Description |
|
|
108
|
+
|----------|-------------|
|
|
109
|
+
| `AI_SUPPORT_AGENT_API_URL` | Override the server URL from config |
|
|
110
|
+
| `AI_SUPPORT_AGENT_TOKEN` | Override the auth token from config |
|
|
111
|
+
|
|
112
|
+
Environment variables have the lowest priority (CLI args > config file > env vars).
|
|
113
|
+
|
|
114
|
+
## Language / i18n
|
|
115
|
+
|
|
116
|
+
The CLI supports English and Japanese. Language is determined in the following order:
|
|
117
|
+
|
|
118
|
+
1. `--lang` flag on any command (e.g., `ai-support-agent start --lang ja`)
|
|
119
|
+
2. Value set via `ai-support-agent set-language <lang>`
|
|
120
|
+
3. Auto-detection from OS locale (`LANG`, `LC_ALL`, or `LC_MESSAGES`)
|
|
121
|
+
4. Default: `en`
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Set language to Japanese
|
|
125
|
+
ai-support-agent set-language ja
|
|
126
|
+
|
|
127
|
+
# Run a single command in Japanese
|
|
128
|
+
ai-support-agent status --lang ja
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Security
|
|
132
|
+
|
|
133
|
+
- **Config file permissions**: The configuration file is created with mode `0o600` (owner read/write only)
|
|
134
|
+
- **Localhost-only auth server**: The OAuth callback server binds to `127.0.0.1` and shuts down immediately after receiving the callback
|
|
135
|
+
- **CSRF nonce protection**: Each login flow generates a unique nonce to prevent cross-site request forgery
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Clone the repository
|
|
141
|
+
git clone https://github.com/mbc-net/ai-support-agent-client.git
|
|
142
|
+
cd ai-support-agent-client
|
|
143
|
+
|
|
144
|
+
# Install dependencies
|
|
145
|
+
npm install
|
|
146
|
+
|
|
147
|
+
# Run in development mode
|
|
148
|
+
npm run dev -- start --verbose
|
|
149
|
+
|
|
150
|
+
# Run tests
|
|
151
|
+
npm test
|
|
152
|
+
|
|
153
|
+
# Run tests with coverage
|
|
154
|
+
npm run test:cov
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProjectRegistration, SystemInfo } from './types';
|
|
2
|
+
export interface RunnerOptions {
|
|
3
|
+
token?: string;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
pollInterval?: number;
|
|
6
|
+
heartbeatInterval?: number;
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function getSystemInfo(): SystemInfo;
|
|
10
|
+
export declare function getLocalIpAddress(): string | undefined;
|
|
11
|
+
export declare function startProjectAgent(project: ProjectRegistration, agentId: string, options: {
|
|
12
|
+
pollInterval: number;
|
|
13
|
+
heartbeatInterval: number;
|
|
14
|
+
}): {
|
|
15
|
+
stop: () => void;
|
|
16
|
+
};
|
|
17
|
+
export declare function setupShutdownHandlers(agents: {
|
|
18
|
+
stop: () => void;
|
|
19
|
+
}[]): void;
|
|
20
|
+
export declare function startAgent(options: RunnerOptions): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=agent-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../src/agent-runner.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAG9D,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,aAAa,IAAI,UAAU,CAS1C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAUtD;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IACP,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,GACA;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAmGtB;AAYD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,EAAE,GAAG,IAAI,CAS1E;AAiBD,wBAAsB,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFtE"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getSystemInfo = getSystemInfo;
|
|
37
|
+
exports.getLocalIpAddress = getLocalIpAddress;
|
|
38
|
+
exports.startProjectAgent = startProjectAgent;
|
|
39
|
+
exports.setupShutdownHandlers = setupShutdownHandlers;
|
|
40
|
+
exports.startAgent = startAgent;
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
|
+
const api_client_1 = require("./api-client");
|
|
43
|
+
const constants_1 = require("./constants");
|
|
44
|
+
const command_executor_1 = require("./command-executor");
|
|
45
|
+
const config_manager_1 = require("./config-manager");
|
|
46
|
+
const i18n_1 = require("./i18n");
|
|
47
|
+
const logger_1 = require("./logger");
|
|
48
|
+
const utils_1 = require("./utils");
|
|
49
|
+
function getSystemInfo() {
|
|
50
|
+
const cpus = os.cpus();
|
|
51
|
+
return {
|
|
52
|
+
platform: os.platform(),
|
|
53
|
+
arch: os.arch(),
|
|
54
|
+
cpuUsage: cpus.length > 0 ? (os.loadavg()[0] / cpus.length) * 100 : 0,
|
|
55
|
+
memoryUsage: (1 - os.freemem() / os.totalmem()) * 100,
|
|
56
|
+
uptime: os.uptime(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function getLocalIpAddress() {
|
|
60
|
+
const interfaces = os.networkInterfaces();
|
|
61
|
+
for (const name of Object.keys(interfaces)) {
|
|
62
|
+
for (const iface of interfaces[name] ?? []) {
|
|
63
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
64
|
+
return iface.address;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
function startProjectAgent(project, agentId, options) {
|
|
71
|
+
const client = new api_client_1.ApiClient(project.apiUrl, project.token);
|
|
72
|
+
const prefix = `[${project.projectCode}]`;
|
|
73
|
+
let heartbeatTimer = null;
|
|
74
|
+
let pollTimer = null;
|
|
75
|
+
let processing = false;
|
|
76
|
+
// 1. Register
|
|
77
|
+
const registerAndStart = async () => {
|
|
78
|
+
try {
|
|
79
|
+
const result = await client.register({
|
|
80
|
+
agentId,
|
|
81
|
+
hostname: os.hostname(),
|
|
82
|
+
os: os.platform(),
|
|
83
|
+
arch: os.arch(),
|
|
84
|
+
ipAddress: getLocalIpAddress(),
|
|
85
|
+
});
|
|
86
|
+
logger_1.logger.success((0, i18n_1.t)('runner.registered', { prefix, agentId: result.agentId }));
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
logger_1.logger.error((0, i18n_1.t)('runner.registerFailed', { prefix, message: (0, utils_1.getErrorMessage)(error) }));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// 2. Heartbeat loop
|
|
93
|
+
const sendHeartbeat = async () => {
|
|
94
|
+
try {
|
|
95
|
+
await client.heartbeat(agentId, getSystemInfo());
|
|
96
|
+
logger_1.logger.debug(`${prefix} Heartbeat sent`);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
logger_1.logger.warn((0, i18n_1.t)('runner.heartbeatFailed', { prefix, message: (0, utils_1.getErrorMessage)(error) }));
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
heartbeatTimer = setInterval(() => {
|
|
103
|
+
void sendHeartbeat();
|
|
104
|
+
}, options.heartbeatInterval);
|
|
105
|
+
void sendHeartbeat();
|
|
106
|
+
// 3. Command polling loop
|
|
107
|
+
const pollCommands = async () => {
|
|
108
|
+
if (processing)
|
|
109
|
+
return;
|
|
110
|
+
processing = true;
|
|
111
|
+
try {
|
|
112
|
+
const pending = await client.getPendingCommands();
|
|
113
|
+
for (const cmd of pending) {
|
|
114
|
+
logger_1.logger.info((0, i18n_1.t)('runner.commandReceived', { prefix, type: cmd.type, commandId: cmd.commandId }));
|
|
115
|
+
try {
|
|
116
|
+
const detail = await client.getCommand(cmd.commandId);
|
|
117
|
+
const result = await (0, command_executor_1.executeCommand)(detail.type, detail.payload);
|
|
118
|
+
await client.submitResult(cmd.commandId, result);
|
|
119
|
+
logger_1.logger.info((0, i18n_1.t)('runner.commandDone', {
|
|
120
|
+
prefix,
|
|
121
|
+
commandId: cmd.commandId,
|
|
122
|
+
result: result.success ? 'success' : 'failed',
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
const message = (0, utils_1.getErrorMessage)(error);
|
|
127
|
+
logger_1.logger.error((0, i18n_1.t)('runner.commandError', { prefix, commandId: cmd.commandId, message }));
|
|
128
|
+
try {
|
|
129
|
+
await client.submitResult(cmd.commandId, {
|
|
130
|
+
success: false,
|
|
131
|
+
error: message,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
logger_1.logger.error((0, i18n_1.t)('runner.resultSendFailed', { prefix }));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
logger_1.logger.debug(`${prefix} Polling error: ${(0, utils_1.getErrorMessage)(error)}`);
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
processing = false;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
pollTimer = setInterval(() => {
|
|
148
|
+
void pollCommands();
|
|
149
|
+
}, options.pollInterval);
|
|
150
|
+
};
|
|
151
|
+
registerAndStart().catch((error) => {
|
|
152
|
+
logger_1.logger.error((0, i18n_1.t)('runner.unexpectedError', { message: (0, utils_1.getErrorMessage)(error) }));
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
stop: () => {
|
|
156
|
+
if (heartbeatTimer)
|
|
157
|
+
clearInterval(heartbeatTimer);
|
|
158
|
+
if (pollTimer)
|
|
159
|
+
clearInterval(pollTimer);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function resolveIntervals(options) {
|
|
164
|
+
return {
|
|
165
|
+
pollInterval: options.pollInterval ?? constants_1.DEFAULT_POLL_INTERVAL,
|
|
166
|
+
heartbeatInterval: options.heartbeatInterval ?? constants_1.DEFAULT_HEARTBEAT_INTERVAL,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function setupShutdownHandlers(agents) {
|
|
170
|
+
const shutdown = () => {
|
|
171
|
+
logger_1.logger.info((0, i18n_1.t)('runner.shuttingDown'));
|
|
172
|
+
agents.forEach((a) => a.stop());
|
|
173
|
+
logger_1.logger.success((0, i18n_1.t)('runner.stopped'));
|
|
174
|
+
process.exit(0);
|
|
175
|
+
};
|
|
176
|
+
process.on('SIGINT', shutdown);
|
|
177
|
+
process.on('SIGTERM', shutdown);
|
|
178
|
+
}
|
|
179
|
+
function runSingleProject(project, agentId, options) {
|
|
180
|
+
const { pollInterval, heartbeatInterval } = resolveIntervals(options);
|
|
181
|
+
logger_1.logger.info((0, i18n_1.t)('runner.starting'));
|
|
182
|
+
const agent = startProjectAgent(project, agentId, { pollInterval, heartbeatInterval });
|
|
183
|
+
logger_1.logger.info((0, i18n_1.t)('runner.startedSingle', { pollInterval, heartbeatInterval }));
|
|
184
|
+
logger_1.logger.info((0, i18n_1.t)('runner.stopHint'));
|
|
185
|
+
setupShutdownHandlers([agent]);
|
|
186
|
+
}
|
|
187
|
+
async function startAgent(options) {
|
|
188
|
+
if (options.verbose) {
|
|
189
|
+
logger_1.logger.setVerbose(true);
|
|
190
|
+
}
|
|
191
|
+
const config = (0, config_manager_1.loadConfig)();
|
|
192
|
+
// Environment variable support (lowest priority)
|
|
193
|
+
const envToken = process.env.AI_SUPPORT_AGENT_TOKEN;
|
|
194
|
+
const envApiUrl = process.env.AI_SUPPORT_AGENT_API_URL;
|
|
195
|
+
// CLI args > config > env vars
|
|
196
|
+
if (options.token && options.apiUrl) {
|
|
197
|
+
const urlError = (0, utils_1.validateApiUrl)(options.apiUrl);
|
|
198
|
+
if (urlError) {
|
|
199
|
+
logger_1.logger.error(urlError);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
logger_1.logger.warn((0, i18n_1.t)('runner.cliTokenWarning'));
|
|
203
|
+
const agentId = config?.agentId ?? os.hostname();
|
|
204
|
+
const project = {
|
|
205
|
+
projectCode: constants_1.PROJECT_CODE_CLI_DIRECT,
|
|
206
|
+
token: options.token,
|
|
207
|
+
apiUrl: options.apiUrl,
|
|
208
|
+
};
|
|
209
|
+
runSingleProject(project, agentId, options);
|
|
210
|
+
(0, config_manager_1.saveConfig)({ lastConnected: new Date().toISOString() });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// Multi-project config
|
|
214
|
+
if (!config) {
|
|
215
|
+
// Fall back to env vars if no config
|
|
216
|
+
if (envToken && envApiUrl) {
|
|
217
|
+
const envUrlError = (0, utils_1.validateApiUrl)(envApiUrl);
|
|
218
|
+
if (envUrlError) {
|
|
219
|
+
logger_1.logger.error(envUrlError);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
logger_1.logger.info((0, i18n_1.t)('runner.envTokenWarning'));
|
|
223
|
+
const project = {
|
|
224
|
+
projectCode: constants_1.PROJECT_CODE_ENV_DEFAULT,
|
|
225
|
+
token: envToken,
|
|
226
|
+
apiUrl: envApiUrl,
|
|
227
|
+
};
|
|
228
|
+
runSingleProject(project, os.hostname(), options);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
logger_1.logger.error((0, i18n_1.t)('runner.noToken'));
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
const projects = (0, config_manager_1.getProjectList)(config);
|
|
235
|
+
if (projects.length === 0) {
|
|
236
|
+
logger_1.logger.error((0, i18n_1.t)('runner.noProjects'));
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
const agentId = config.agentId ?? os.hostname();
|
|
240
|
+
const { pollInterval, heartbeatInterval } = resolveIntervals(options);
|
|
241
|
+
logger_1.logger.info((0, i18n_1.t)('runner.startingMulti', { count: projects.length }));
|
|
242
|
+
const agents = projects.map((project) => startProjectAgent(project, agentId, { pollInterval, heartbeatInterval }));
|
|
243
|
+
(0, config_manager_1.saveConfig)({ lastConnected: new Date().toISOString() });
|
|
244
|
+
logger_1.logger.info((0, i18n_1.t)('runner.startedMulti', { count: projects.length, pollInterval, heartbeatInterval }));
|
|
245
|
+
for (const p of projects) {
|
|
246
|
+
logger_1.logger.info(` - ${p.projectCode} (${p.apiUrl})`);
|
|
247
|
+
}
|
|
248
|
+
logger_1.logger.info((0, i18n_1.t)('runner.stopHint'));
|
|
249
|
+
setupShutdownHandlers(agents);
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=agent-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-runner.js","sourceRoot":"","sources":["../src/agent-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentCommand, CommandResult, PendingCommand, RegisterRequest, RegisterResponse, SystemInfo } from './types';
|
|
2
|
+
export declare class ApiClient {
|
|
3
|
+
private readonly client;
|
|
4
|
+
constructor(apiUrl: string, token: string);
|
|
5
|
+
private shouldRetry;
|
|
6
|
+
private withRetry;
|
|
7
|
+
register(request: RegisterRequest): Promise<RegisterResponse>;
|
|
8
|
+
heartbeat(agentId: string, systemInfo: SystemInfo): Promise<void>;
|
|
9
|
+
getPendingCommands(): Promise<PendingCommand[]>;
|
|
10
|
+
private validateCommandId;
|
|
11
|
+
getCommand(commandId: string): Promise<AgentCommand>;
|
|
12
|
+
submitResult(commandId: string, result: CommandResult): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,UAAU,EACX,MAAM,SAAS,CAAA;AAEhB,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAgBzC,OAAO,CAAC,WAAW;YAcL,SAAS;IAqBjB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgB7D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjE,kBAAkB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAUrD,OAAO,CAAC,iBAAiB;IAMnB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAWpD,YAAY,CAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC;CAOjB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ApiClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
const logger_1 = require("./logger");
|
|
10
|
+
class ApiClient {
|
|
11
|
+
client;
|
|
12
|
+
constructor(apiUrl, token) {
|
|
13
|
+
const parsed = new URL(apiUrl);
|
|
14
|
+
if (parsed.protocol === 'http:' && parsed.hostname !== '127.0.0.1' && parsed.hostname !== 'localhost') {
|
|
15
|
+
logger_1.logger.warn('API URL uses HTTP (not HTTPS). Token may be transmitted in plain text.');
|
|
16
|
+
}
|
|
17
|
+
this.client = axios_1.default.create({
|
|
18
|
+
baseURL: apiUrl,
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${token}`,
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
timeout: constants_1.API_REQUEST_TIMEOUT,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
shouldRetry(error) {
|
|
27
|
+
if (!axios_1.default.isAxiosError(error) || !error.response) {
|
|
28
|
+
return true; // Network error — retry
|
|
29
|
+
}
|
|
30
|
+
const status = error.response.status;
|
|
31
|
+
if (status === 408 || status === 429) {
|
|
32
|
+
return true; // Timeout / rate-limit — retry
|
|
33
|
+
}
|
|
34
|
+
if (status >= 500) {
|
|
35
|
+
return true; // Server error — retry
|
|
36
|
+
}
|
|
37
|
+
return false; // Other 4xx — do not retry
|
|
38
|
+
}
|
|
39
|
+
async withRetry(fn) {
|
|
40
|
+
let lastError;
|
|
41
|
+
for (let attempt = 0; attempt < constants_1.API_MAX_RETRIES; attempt++) {
|
|
42
|
+
try {
|
|
43
|
+
return await fn();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
lastError = error;
|
|
47
|
+
if (!this.shouldRetry(error)) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
if (attempt < constants_1.API_MAX_RETRIES - 1) {
|
|
51
|
+
const baseDelay = constants_1.API_BASE_DELAY_MS * Math.pow(2, attempt);
|
|
52
|
+
const delay = Math.round(baseDelay * (0.5 + Math.random() * 0.5));
|
|
53
|
+
logger_1.logger.debug(`Request failed (attempt ${attempt + 1}/${constants_1.API_MAX_RETRIES}), retrying in ${delay}ms`);
|
|
54
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
throw lastError;
|
|
59
|
+
}
|
|
60
|
+
async register(request) {
|
|
61
|
+
logger_1.logger.debug(`Registering agent: ${request.agentId}`);
|
|
62
|
+
return this.withRetry(async () => {
|
|
63
|
+
const { ipAddress, ...rest } = request;
|
|
64
|
+
const { data } = await this.client.post(constants_1.API_ENDPOINTS.REGISTER, {
|
|
65
|
+
...rest,
|
|
66
|
+
version: constants_1.AGENT_VERSION,
|
|
67
|
+
...(ipAddress && { ipAddress }),
|
|
68
|
+
});
|
|
69
|
+
return data;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async heartbeat(agentId, systemInfo) {
|
|
73
|
+
logger_1.logger.debug('Sending heartbeat');
|
|
74
|
+
await this.withRetry(async () => {
|
|
75
|
+
await this.client.post(constants_1.API_ENDPOINTS.HEARTBEAT, {
|
|
76
|
+
agentId,
|
|
77
|
+
timestamp: Date.now(),
|
|
78
|
+
version: constants_1.AGENT_VERSION,
|
|
79
|
+
systemInfo,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async getPendingCommands() {
|
|
84
|
+
logger_1.logger.debug('Polling for pending commands');
|
|
85
|
+
return this.withRetry(async () => {
|
|
86
|
+
const { data } = await this.client.get(constants_1.API_ENDPOINTS.COMMANDS_PENDING);
|
|
87
|
+
return data;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
validateCommandId(commandId) {
|
|
91
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(commandId)) {
|
|
92
|
+
throw new Error(`Invalid command ID format: ${commandId}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async getCommand(commandId) {
|
|
96
|
+
this.validateCommandId(commandId);
|
|
97
|
+
logger_1.logger.debug(`Fetching command: ${commandId}`);
|
|
98
|
+
return this.withRetry(async () => {
|
|
99
|
+
const { data } = await this.client.get(constants_1.API_ENDPOINTS.COMMAND(commandId));
|
|
100
|
+
return data;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async submitResult(commandId, result) {
|
|
104
|
+
this.validateCommandId(commandId);
|
|
105
|
+
logger_1.logger.debug(`Submitting result for command: ${commandId}`);
|
|
106
|
+
await this.withRetry(async () => {
|
|
107
|
+
await this.client.post(constants_1.API_ENDPOINTS.COMMAND_RESULT(commandId), result);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.ApiClient = ApiClient;
|
|
112
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface AuthResult {
|
|
2
|
+
token: string;
|
|
3
|
+
apiUrl?: string;
|
|
4
|
+
projectCode?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function startAuthServer(port?: number, allowedOrigin?: string): Promise<{
|
|
7
|
+
url: string;
|
|
8
|
+
nonce: string;
|
|
9
|
+
waitForCallback: () => Promise<AuthResult>;
|
|
10
|
+
stop: () => void;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=auth-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-server.d.ts","sourceRoot":"","sources":["../src/auth-server.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;IAC1C,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAC,CA2HD"}
|