@bpinhosilva/agent-orchestrator 1.1.2 → 1.2.0
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 +21 -0
- package/README.md +7 -0
- package/dist/cli/commands/run.command.js +20 -1
- package/dist/cli/commands/setup.command.js +13 -0
- package/dist/cli/constants.js +2 -1
- package/dist/cli/env.js +2 -0
- package/dist/cli/preload.js +12 -0
- package/dist/cli/process-manager.js +33 -29
- package/dist/cli/setup/index.js +24 -0
- package/dist/cli/setup/validators.js +14 -0
- package/dist/common/postman/postman-conversion.js +57 -0
- package/dist/config/env.validation.js +6 -0
- package/dist/config/runtime-logger.js +214 -0
- package/dist/main.js +8 -0
- package/dist/tasks/recurrent-task-scheduler.service.js +3 -4
- package/dist/ui/assets/{AgentFleet-BarfEwcK.js → AgentFleet-B8p5vbKK.js} +1 -1
- package/dist/ui/assets/{AttachmentItem-Cerhbyya.js → AttachmentItem-C_uUACPz.js} +1 -1
- package/dist/ui/assets/{ConfirmDialog-y3vTcqFR.js → ConfirmDialog-BltdtevE.js} +1 -1
- package/dist/ui/assets/{CreateRecurrentTaskModal-BgfnJ1n8.js → CreateRecurrentTaskModal-CGSdgNAf.js} +1 -1
- package/dist/ui/assets/{CreateTaskModal-BH9lOLYT.js → CreateTaskModal-XNvIWKz3.js} +1 -1
- package/dist/ui/assets/{ExecLogModal-ShacCOOV.js → ExecLogModal-BYTGF04P.js} +1 -1
- package/dist/ui/assets/{MarkdownField--1gpyapw.js → MarkdownField-DR6tHsei.js} +1 -1
- package/dist/ui/assets/{Profile-qnuRN5Qv.js → Profile-ByioVLM8.js} +1 -1
- package/dist/ui/assets/{ProjectDetail-ZYQG9yn2.js → ProjectDetail-dwZDzb0m.js} +1 -1
- package/dist/ui/assets/{Providers-DR7srJHq.js → Providers-JAClEFt0.js} +1 -1
- package/dist/ui/assets/{Scheduler-Bs3DC0re.js → Scheduler-C1HQNxQ6.js} +2 -2
- package/dist/ui/assets/{Settings-C3ad44vP.js → Settings-Cjn2xdo1.js} +1 -1
- package/dist/ui/assets/{TaskDetail-D-f_Ao2a.js → TaskDetail-Blphf9tw.js} +1 -1
- package/dist/ui/assets/{TaskExecutions-BeodRIz1.js → TaskExecutions-ydR4KPCY.js} +3 -3
- package/dist/ui/assets/{TaskManager-BA2Y31ut.js → TaskManager-DrFbuAwN.js} +3 -3
- package/dist/ui/assets/{UserDetail-BvWm-U4y.js → UserDetail-mWjJPTzO.js} +1 -1
- package/dist/ui/assets/{Users-CQNcXLyV.js → Users-FaX0thJx.js} +1 -1
- package/dist/ui/assets/{activity-CmAajKmR.js → activity-B_2QSywM.js} +1 -1
- package/dist/ui/assets/{agents-b8btewki.js → agents-YQJ7JNfI.js} +1 -1
- package/dist/ui/assets/{auth-dROenHXk.js → auth-Lh2N3iYN.js} +1 -1
- package/dist/ui/assets/{bot-QVmnxPf4.js → bot-DadO9w3D.js} +1 -1
- package/dist/ui/assets/{box-Bw_pyYzU.js → box-CFDcDxHv.js} +1 -1
- package/dist/ui/assets/{brain-C6vlLcg3.js → brain-DWTpby6b.js} +1 -1
- package/dist/ui/assets/{briefcase-DtHlat45.js → briefcase-mFWNV6w9.js} +1 -1
- package/dist/ui/assets/check-BiORptL3.js +1 -0
- package/dist/ui/assets/chevron-down-BUOg3vvd.js +1 -0
- package/dist/ui/assets/chevron-left-B0NmQyxK.js +1 -0
- package/dist/ui/assets/chevron-right-Bm_d1KKk.js +1 -0
- package/dist/ui/assets/{circle-alert-pUx6yhcF.js → circle-alert-sCcf7ANF.js} +1 -1
- package/dist/ui/assets/circle-check-Jz8IOE4h.js +1 -0
- package/dist/ui/assets/client-B553SX3l.js +9 -0
- package/dist/ui/assets/clock-CSNFJjo4.js +1 -0
- package/dist/ui/assets/{cpu-8Sbc9Dk0.js → cpu-C2_GFeSH.js} +1 -1
- package/dist/ui/assets/{database-D6O4hvbm.js → database-zXW48-_N.js} +1 -1
- package/dist/ui/assets/{download-DHcd5oLD.js → download-DZdOdijy.js} +1 -1
- package/dist/ui/assets/{eye-Cc-vy4Zu.js → eye-CjrFwZG_.js} +1 -1
- package/dist/ui/assets/{file-text-DWBSXx5l.js → file-text-CX_Yqfjf.js} +1 -1
- package/dist/ui/assets/{index-BvUv9Lzq.js → index-IcLlFUZs.js} +3 -3
- package/dist/ui/assets/{info-1jA6X-_e.js → info-DGHChFI6.js} +1 -1
- package/dist/ui/assets/{layers-BcHXXg-4.js → layers-CVf8_Byb.js} +1 -1
- package/dist/ui/assets/loader-circle-CB6PQwdc.js +1 -0
- package/dist/ui/assets/{panels-top-left-Vk8FzAxf.js → panels-top-left-Cp169WzB.js} +1 -1
- package/dist/ui/assets/{paperclip-DWJjaP8B.js → paperclip-5Y367YTj.js} +1 -1
- package/dist/ui/assets/plus-CkteVqhM.js +1 -0
- package/dist/ui/assets/{projects-CUOthD8N.js → projects-DoalTI7c.js} +1 -1
- package/dist/ui/assets/{providers-CNrSTcdc.js → providers-AawjMy3x.js} +1 -1
- package/dist/ui/assets/{recurrent-tasks-CKT47N2l.js → recurrent-tasks-7thk45mk.js} +1 -1
- package/dist/ui/assets/{refresh-cw-DQW6jR7M.js → refresh-cw-BgDsJOC_.js} +1 -1
- package/dist/ui/assets/{rocket-CMSwBl_C.js → rocket-B9Iexkcw.js} +1 -1
- package/dist/ui/assets/{save-DycJmlX0.js → save-Cmqi1IkN.js} +1 -1
- package/dist/ui/assets/{send-BZjwSrJW.js → send-iK1X7WSe.js} +1 -1
- package/dist/ui/assets/{server-CJE2K1Vt.js → server-BBmM-vrg.js} +1 -1
- package/dist/ui/assets/{settings-at7JqFrc.js → settings-BpKLGxm8.js} +1 -1
- package/dist/ui/assets/{shield-alert-CP5GVXxa.js → shield-alert-Do_Sg9SX.js} +1 -1
- package/dist/ui/assets/{shield-check-Cr4SHjdR.js → shield-check-YKs9kUNq.js} +1 -1
- package/dist/ui/assets/{sparkles-v57Nc-z-.js → sparkles-krUpxie4.js} +1 -1
- package/dist/ui/assets/{taskFormSchemas-dl1t1OyX.js → taskFormSchemas-B6YlRxrx.js} +1 -1
- package/dist/ui/assets/{tasks-DEUQCNoH.js → tasks-DHsBE-ea.js} +1 -1
- package/dist/ui/assets/{terminal-a6AV2mPO.js → terminal-B6iyNuAm.js} +1 -1
- package/dist/ui/assets/{trash-2-DJpTXgEP.js → trash-2-CphQfk35.js} +1 -1
- package/dist/ui/assets/{trending-up-DlrXEXE6.js → trending-up-ClGbkbN9.js} +1 -1
- package/dist/ui/assets/user-Brcjlps5.js +1 -0
- package/dist/ui/assets/{user-plus-nDkwsBT1.js → user-plus-0Y0M1GKi.js} +1 -1
- package/dist/ui/assets/{users-C6WiDiuN.js → users-BcnlUG5N.js} +1 -1
- package/dist/ui/assets/{users-Ef6Sh2iR.js → users-tdyaGZbx.js} +1 -1
- package/dist/ui/assets/x-CCZGYGDC.js +1 -0
- package/dist/ui/assets/{zap-BmhZqgvm.js → zap-BDAytXMX.js} +1 -1
- package/dist/ui/index.html +17 -17
- package/package.json +9 -4
- package/dist/ui/assets/check-DTei8Qlg.js +0 -1
- package/dist/ui/assets/chevron-down-LTeQHW9O.js +0 -1
- package/dist/ui/assets/chevron-left-CJc_eQid.js +0 -1
- package/dist/ui/assets/chevron-right-G5-HRo_C.js +0 -1
- package/dist/ui/assets/circle-check-B9kyRki5.js +0 -1
- package/dist/ui/assets/client-BGOBXkO8.js +0 -9
- package/dist/ui/assets/clock-BY4rrypg.js +0 -1
- package/dist/ui/assets/loader-circle-Cl6yIkPK.js +0 -1
- package/dist/ui/assets/plus-Dx6G8SOZ.js +0 -1
- package/dist/ui/assets/user--KOoEB9m.js +0 -1
- package/dist/ui/assets/x-wDy15QMx.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [1.2.0](https://github.com/bpinhosilva/agent-orchestrator/compare/v1.1.3...v1.2.0) (2026-05-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **tests:** move startServer tests to isolated spec using jest.mock ([8ede64a](https://github.com/bpinhosilva/agent-orchestrator/commit/8ede64a8e68175bbbe6ed3c076b682cd8412c25e))
|
|
7
|
+
* **ui:** add missing test peers ([8c3d1a8](https://github.com/bpinhosilva/agent-orchestrator/commit/8c3d1a8b6941d5eb6e0ca38e7645c7b6b56b314a))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **cli:** add runtime log rotation ([7ccd9f2](https://github.com/bpinhosilva/agent-orchestrator/commit/7ccd9f23a19ee8de0d5c000b178f2b4d9e990f08))
|
|
13
|
+
|
|
14
|
+
## [1.1.3](https://github.com/bpinhosilva/agent-orchestrator/compare/v1.1.2...v1.1.3) (2026-05-02)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* add UUID support and Postman collection generation ([a4bfd77](https://github.com/bpinhosilva/agent-orchestrator/commit/a4bfd7733d7a28ba3bc06748a6dce1ca27c5c466))
|
|
20
|
+
* update cron job handling to replace inactive jobs for active tasks ([3d01155](https://github.com/bpinhosilva/agent-orchestrator/commit/3d01155f3f8f5be127e2bace79ede889502e4ec8))
|
|
21
|
+
|
|
1
22
|
## [1.1.2](https://github.com/bpinhosilva/agent-orchestrator/compare/v1.1.1...v1.1.2) (2026-04-21)
|
|
2
23
|
|
|
3
24
|
|
package/README.md
CHANGED
|
@@ -132,6 +132,9 @@ DB_LOGGING=false
|
|
|
132
132
|
SERVE_STATIC_UI=true
|
|
133
133
|
CHECK_PENDING_MIGRATIONS_ON_STARTUP=false
|
|
134
134
|
LOG_LEVEL=error
|
|
135
|
+
# Optional packaged-runtime / Docker file-rotation settings
|
|
136
|
+
# LOG_ROTATION_MAX_SIZE_MB=10
|
|
137
|
+
# LOG_ROTATION_MAX_FILES=4
|
|
135
138
|
```
|
|
136
139
|
|
|
137
140
|
## Database setup
|
|
@@ -215,6 +218,8 @@ agent-orchestrator rotate-secrets
|
|
|
215
218
|
|
|
216
219
|
When running the packaged app or a production build with static UI enabled, the dashboard is served from `http://localhost:15789` by default.
|
|
217
220
|
|
|
221
|
+
By default, the packaged CLI/runtime keeps writing to `${AGENT_ORCHESTRATOR_HOME}/server.log`, rotating the active file at **10 MB** and retaining **4** timestamped archives. You can persist different defaults with `agent-orchestrator setup --log-max-size-mb <mb> --log-max-files <count>` and override them for a single launch with `agent-orchestrator run --log-max-size-mb <mb> --log-max-files <count>`.
|
|
222
|
+
|
|
218
223
|
## Docker
|
|
219
224
|
|
|
220
225
|
> For the full Docker guide, see [docs/DOCKER.md](docs/DOCKER.md).
|
|
@@ -227,6 +232,8 @@ The repository ships three Compose entrypoints:
|
|
|
227
232
|
| `docker-compose.dev.yml` | Development stack with API hot reload and Vite UI dev server |
|
|
228
233
|
| `docker-compose.test.yml` | Integration stack for migration, CLI/runtime, API, and UI checks |
|
|
229
234
|
|
|
235
|
+
Docker keeps stdout/stderr as the primary log stream, so `docker compose logs` continues to work as before. If you also want rotated in-container log files, set `LOG_ROTATION_MAX_SIZE_MB` and `LOG_ROTATION_MAX_FILES`; the API container writes to the system temp directory by default (typically `/tmp/server.log`), or `${AGENT_ORCHESTRATOR_HOME}/server.log` if you set a writable runtime home.
|
|
236
|
+
|
|
230
237
|
### Production-style stack
|
|
231
238
|
|
|
232
239
|
**Step 1: Create `.env`** — copy the example in the repo root and fill in your values:
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerRunCommand = registerRunCommand;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
|
+
const validators_1 = require("../setup/validators");
|
|
5
6
|
const process_manager_1 = require("../process-manager");
|
|
6
7
|
const migration_state_1 = require("../../database/migration-state");
|
|
7
8
|
const constants_1 = require("../constants");
|
|
@@ -18,6 +19,8 @@ function registerRunCommand(program) {
|
|
|
18
19
|
.command('run')
|
|
19
20
|
.description('Start the orchestrator server in detached mode')
|
|
20
21
|
.option('--log-level <level>', 'Set the log level (fatal, error, warn, log, debug, verbose)')
|
|
22
|
+
.option('--log-max-size-mb <mb>', 'One-off override: max log file size in MB before rotation', (v) => (0, validators_1.parsePositiveInt)(v) ?? Number.NaN)
|
|
23
|
+
.option('--log-max-files <count>', 'One-off override: max number of rotated log files to keep', (v) => (0, validators_1.parsePositiveInt)(v) ?? Number.NaN)
|
|
21
24
|
.action(async (...args) => {
|
|
22
25
|
try {
|
|
23
26
|
const options = (0, utils_1.resolveActionOptions)(args);
|
|
@@ -26,6 +29,18 @@ function registerRunCommand(program) {
|
|
|
26
29
|
throw new Error(`Invalid log level "${options.logLevel}". Valid values: ${VALID_LOG_LEVELS.join(', ')}`);
|
|
27
30
|
}
|
|
28
31
|
}
|
|
32
|
+
if (options.logMaxSizeMb !== undefined) {
|
|
33
|
+
if (!Number.isInteger(options.logMaxSizeMb) ||
|
|
34
|
+
options.logMaxSizeMb <= 0) {
|
|
35
|
+
throw new Error(`Invalid --log-max-size-mb "${options.logMaxSizeMb}". Must be a positive integer.`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (options.logMaxFiles !== undefined) {
|
|
39
|
+
if (!Number.isInteger(options.logMaxFiles) ||
|
|
40
|
+
options.logMaxFiles <= 0) {
|
|
41
|
+
throw new Error(`Invalid --log-max-files "${options.logMaxFiles}". Must be a positive integer.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
29
44
|
// Check for pending migrations before starting
|
|
30
45
|
const { hasPending } = await (0, migration_state_1.checkPendingMigrations)({
|
|
31
46
|
assumePendingOnError: true,
|
|
@@ -44,7 +59,11 @@ function registerRunCommand(program) {
|
|
|
44
59
|
return;
|
|
45
60
|
}
|
|
46
61
|
console.log('Starting Agent Orchestrator in background...');
|
|
47
|
-
const { pid, host, port } = (0, process_manager_1.startServer)({
|
|
62
|
+
const { pid, host, port } = (0, process_manager_1.startServer)({
|
|
63
|
+
logLevel: options.logLevel,
|
|
64
|
+
logMaxSizeMb: options.logMaxSizeMb,
|
|
65
|
+
logMaxFiles: options.logMaxFiles,
|
|
66
|
+
});
|
|
48
67
|
const survived = await (0, utils_1.verifyServerStartup)(pid);
|
|
49
68
|
if (!survived) {
|
|
50
69
|
process.exit(1);
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registerSetupCommand = registerSetupCommand;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
5
|
const index_1 = require("../setup/index");
|
|
6
|
+
const validators_1 = require("../setup/validators");
|
|
6
7
|
const migration_state_1 = require("../../database/migration-state");
|
|
7
8
|
function registerSetupCommand(program) {
|
|
8
9
|
program
|
|
@@ -27,10 +28,22 @@ function registerSetupCommand(program) {
|
|
|
27
28
|
.option('--admin-email <email>', 'Admin user email for non-interactive setup')
|
|
28
29
|
.option('--admin-password <password>', 'Admin user password for non-interactive setup')
|
|
29
30
|
.option('--regenerate-jwt-secret', 'Generate a new JWT secret instead of preserving the existing one')
|
|
31
|
+
.option('--log-max-size-mb <mb>', 'Max log file size in MB before rotation (default: 10)', (v) => (0, validators_1.parsePositiveInt)(v) ?? Number.NaN)
|
|
32
|
+
.option('--log-max-files <count>', 'Max number of rotated log files to keep (default: 4)', (v) => (0, validators_1.parsePositiveInt)(v) ?? Number.NaN)
|
|
30
33
|
.action(async (...args) => {
|
|
31
34
|
const opts = (0, utils_1.resolveActionOptions)(args);
|
|
32
35
|
console.log('Starting setup...');
|
|
33
36
|
try {
|
|
37
|
+
if (opts.logMaxSizeMb !== undefined) {
|
|
38
|
+
if (!Number.isInteger(opts.logMaxSizeMb) || opts.logMaxSizeMb <= 0) {
|
|
39
|
+
throw new Error(`Invalid --log-max-size-mb "${opts.logMaxSizeMb}". Must be a positive integer.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (opts.logMaxFiles !== undefined) {
|
|
43
|
+
if (!Number.isInteger(opts.logMaxFiles) || opts.logMaxFiles <= 0) {
|
|
44
|
+
throw new Error(`Invalid --log-max-files "${opts.logMaxFiles}". Must be a positive integer.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
34
47
|
await (0, index_1.handleSetup)(opts);
|
|
35
48
|
if (opts.yes) {
|
|
36
49
|
const { hasPending, isEmpty } = await (0, migration_state_1.checkPendingMigrations)({
|
package/dist/cli/constants.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PROCESS_FILE = exports.ENV_PATH = exports.LOG_FILE = exports.PID_FILE = exports.PID_DIR = exports.UI_INDEX_FILE = exports.MAIN_FILE = exports.PACKAGE_JSON_PATH = exports.PACKAGE_ROOT = exports.SUPPORTED_PROVIDERS = void 0;
|
|
36
|
+
exports.PROCESS_FILE = exports.ENV_PATH = exports.LOG_FILE = exports.PID_FILE = exports.PID_DIR = exports.PRELOAD_FILE = exports.UI_INDEX_FILE = exports.MAIN_FILE = exports.PACKAGE_JSON_PATH = exports.PACKAGE_ROOT = exports.SUPPORTED_PROVIDERS = void 0;
|
|
37
37
|
const os = __importStar(require("os"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
var types_1 = require("./types");
|
|
@@ -42,6 +42,7 @@ exports.PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
|
|
|
42
42
|
exports.PACKAGE_JSON_PATH = path.join(exports.PACKAGE_ROOT, 'package.json');
|
|
43
43
|
exports.MAIN_FILE = path.join(exports.PACKAGE_ROOT, 'dist/main.js');
|
|
44
44
|
exports.UI_INDEX_FILE = path.join(exports.PACKAGE_ROOT, 'dist/ui/index.html');
|
|
45
|
+
exports.PRELOAD_FILE = path.join(exports.PACKAGE_ROOT, 'dist/cli/preload.js');
|
|
45
46
|
// These are set at process start before any imports, so the env var is always present
|
|
46
47
|
exports.PID_DIR = process.env.AGENT_ORCHESTRATOR_HOME ??
|
|
47
48
|
path.join(os.homedir(), '.agent-orchestrator');
|
package/dist/cli/env.js
CHANGED
|
@@ -139,6 +139,8 @@ function buildEnvContent(currentEnv, basicConfig, databaseUrl, geminiKey, anthro
|
|
|
139
139
|
'ANTHROPIC_API_KEY',
|
|
140
140
|
'OLLAMA_HOST',
|
|
141
141
|
'OLLAMA_API_KEY',
|
|
142
|
+
'LOG_ROTATION_MAX_SIZE_MB',
|
|
143
|
+
'LOG_ROTATION_MAX_FILES',
|
|
142
144
|
'JWT_SECRET',
|
|
143
145
|
'JWT_REFRESH_SECRET',
|
|
144
146
|
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const runtime_paths_1 = require("../config/runtime-paths");
|
|
4
|
+
const runtime_logger_1 = require("../config/runtime-logger");
|
|
5
|
+
(0, runtime_paths_1.loadRuntimeEnv)();
|
|
6
|
+
try {
|
|
7
|
+
(0, runtime_logger_1.initRuntimeLogger)();
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
(0, runtime_logger_1.persistRuntimeLoggerInitFailure)(String(err));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
@@ -231,13 +231,16 @@ function getChildEnvironment(pidDir = constants_1.PID_DIR) {
|
|
|
231
231
|
}
|
|
232
232
|
return childEnv;
|
|
233
233
|
}
|
|
234
|
-
function assertBuildExists(mainFile = constants_1.MAIN_FILE, uiIndexFile = constants_1.UI_INDEX_FILE, fsDep = realFs) {
|
|
234
|
+
function assertBuildExists(mainFile = constants_1.MAIN_FILE, uiIndexFile = constants_1.UI_INDEX_FILE, preloadFile = constants_1.PRELOAD_FILE, fsDep = realFs) {
|
|
235
235
|
if (!fsDep.existsSync(mainFile)) {
|
|
236
236
|
throw new Error(`Missing backend build at ${mainFile}. Run "npm run build:all" before using the CLI runtime.`);
|
|
237
237
|
}
|
|
238
238
|
if (!fsDep.existsSync(uiIndexFile)) {
|
|
239
239
|
throw new Error(`Missing UI build at ${uiIndexFile}. Run "npm run build:all" so the packaged CLI starts the full application.`);
|
|
240
240
|
}
|
|
241
|
+
if (!fsDep.existsSync(preloadFile)) {
|
|
242
|
+
throw new Error(`Missing CLI preload build at ${preloadFile}. Run "npm run build:all" before using the CLI runtime.`);
|
|
243
|
+
}
|
|
241
244
|
}
|
|
242
245
|
function isManagedProcess(pid, expected, fsDep = realFs) {
|
|
243
246
|
if (os.platform() === 'win32') {
|
|
@@ -359,7 +362,8 @@ async function stopManagedProcessById(pid, cwd, mainPath, fsDep = realFs) {
|
|
|
359
362
|
* that no instance is already running before calling this.
|
|
360
363
|
*/
|
|
361
364
|
function startServer(options = {}, mainFile = constants_1.MAIN_FILE, packageRoot = constants_1.PACKAGE_ROOT, logFile = constants_1.LOG_FILE, pidDir = constants_1.PID_DIR, envPath = constants_1.ENV_PATH) {
|
|
362
|
-
|
|
365
|
+
const preloadFile = path.join(packageRoot, 'dist/cli/preload.js');
|
|
366
|
+
assertBuildExists(mainFile, constants_1.UI_INDEX_FILE, preloadFile);
|
|
363
367
|
if (!fs.existsSync(pidDir)) {
|
|
364
368
|
fs.mkdirSync(pidDir, { recursive: true, mode: 0o700 });
|
|
365
369
|
}
|
|
@@ -367,32 +371,32 @@ function startServer(options = {}, mainFile = constants_1.MAIN_FILE, packageRoot
|
|
|
367
371
|
if (options.logLevel) {
|
|
368
372
|
env.LOG_LEVEL = options.logLevel;
|
|
369
373
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
cwd: packageRoot,
|
|
376
|
-
env,
|
|
377
|
-
});
|
|
378
|
-
const pid = child.pid;
|
|
379
|
-
if (!pid)
|
|
380
|
-
throw new Error('Failed to determine spawned process PID.');
|
|
381
|
-
const port = getConfiguredPort(envPath);
|
|
382
|
-
const host = getConfiguredHost(envPath);
|
|
383
|
-
persistProcessMetadata({
|
|
384
|
-
pid,
|
|
385
|
-
cwd: packageRoot,
|
|
386
|
-
mainPath: mainFile,
|
|
387
|
-
host,
|
|
388
|
-
port,
|
|
389
|
-
logFile,
|
|
390
|
-
startedAt: new Date().toISOString(),
|
|
391
|
-
});
|
|
392
|
-
child.unref();
|
|
393
|
-
return { pid, host, port };
|
|
394
|
-
}
|
|
395
|
-
finally {
|
|
396
|
-
fs.closeSync(logFd);
|
|
374
|
+
if (options.logMaxSizeMb !== undefined) {
|
|
375
|
+
env.LOG_ROTATION_MAX_SIZE_MB = String(options.logMaxSizeMb);
|
|
376
|
+
}
|
|
377
|
+
if (options.logMaxFiles !== undefined) {
|
|
378
|
+
env.LOG_ROTATION_MAX_FILES = String(options.logMaxFiles);
|
|
397
379
|
}
|
|
380
|
+
const child = (0, child_process_1.spawn)('node', ['--require', preloadFile, mainFile], {
|
|
381
|
+
detached: true,
|
|
382
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
383
|
+
cwd: packageRoot,
|
|
384
|
+
env,
|
|
385
|
+
});
|
|
386
|
+
const pid = child.pid;
|
|
387
|
+
if (!pid)
|
|
388
|
+
throw new Error('Failed to determine spawned process PID.');
|
|
389
|
+
const port = getConfiguredPort(envPath);
|
|
390
|
+
const host = getConfiguredHost(envPath);
|
|
391
|
+
persistProcessMetadata({
|
|
392
|
+
pid,
|
|
393
|
+
cwd: packageRoot,
|
|
394
|
+
mainPath: mainFile,
|
|
395
|
+
host,
|
|
396
|
+
port,
|
|
397
|
+
logFile,
|
|
398
|
+
startedAt: new Date().toISOString(),
|
|
399
|
+
});
|
|
400
|
+
child.unref();
|
|
401
|
+
return { pid, host, port };
|
|
398
402
|
}
|
package/dist/cli/setup/index.js
CHANGED
|
@@ -40,6 +40,8 @@ const env_1 = require("../env");
|
|
|
40
40
|
const host_defaults_1 = require("../../config/host.defaults");
|
|
41
41
|
const admin_1 = require("./admin");
|
|
42
42
|
const prompts_1 = require("./prompts");
|
|
43
|
+
const validators_1 = require("./validators");
|
|
44
|
+
const LOG_ROTATION_DEFAULTS = { maxSizeMb: 10, maxFiles: 4 };
|
|
43
45
|
const SENSITIVE_FLAG_ENV_VARS = [
|
|
44
46
|
['geminiKey', 'GEMINI_API_KEY', '--gemini-key'],
|
|
45
47
|
['anthropicKey', 'ANTHROPIC_API_KEY', '--anthropic-key'],
|
|
@@ -56,8 +58,28 @@ async function handleSetup(opts, fsDep, prompter, dsFactory) {
|
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
const existingEnv = (0, env_1.readEnvFile)(constants_1.ENV_PATH, fsDep);
|
|
61
|
+
if (opts.logMaxSizeMb !== undefined &&
|
|
62
|
+
(!Number.isInteger(opts.logMaxSizeMb) || opts.logMaxSizeMb <= 0)) {
|
|
63
|
+
throw new Error('Invalid logMaxSizeMb. Expected a positive integer.');
|
|
64
|
+
}
|
|
65
|
+
if (opts.logMaxFiles !== undefined &&
|
|
66
|
+
(!Number.isInteger(opts.logMaxFiles) || opts.logMaxFiles <= 0)) {
|
|
67
|
+
throw new Error('Invalid logMaxFiles. Expected a positive integer.');
|
|
68
|
+
}
|
|
59
69
|
// Resolve a sensitive value: CLI flag > process env var > existing .env value
|
|
60
70
|
const resolveSecret = (flagValue, envVar, existingKey) => flagValue ?? process.env[envVar] ?? existingEnv[existingKey] ?? '';
|
|
71
|
+
// Resolve a positive-integer config value: flag > existing env > default
|
|
72
|
+
const resolvePositiveInt = (flagValue, existingKey, defaultValue) => {
|
|
73
|
+
if (flagValue !== undefined &&
|
|
74
|
+
Number.isInteger(flagValue) &&
|
|
75
|
+
flagValue > 0) {
|
|
76
|
+
return flagValue;
|
|
77
|
+
}
|
|
78
|
+
const fromEnv = (0, validators_1.parsePositiveInt)(existingEnv[existingKey]);
|
|
79
|
+
return fromEnv ?? defaultValue;
|
|
80
|
+
};
|
|
81
|
+
const logMaxSizeMb = resolvePositiveInt(opts.logMaxSizeMb, 'LOG_ROTATION_MAX_SIZE_MB', LOG_ROTATION_DEFAULTS.maxSizeMb);
|
|
82
|
+
const logMaxFiles = resolvePositiveInt(opts.logMaxFiles, 'LOG_ROTATION_MAX_FILES', LOG_ROTATION_DEFAULTS.maxFiles);
|
|
61
83
|
let answers;
|
|
62
84
|
if (opts.yes) {
|
|
63
85
|
const jwtSecret = opts.regenerateJwtSecret || !existingEnv.JWT_SECRET
|
|
@@ -87,6 +109,8 @@ async function handleSetup(opts, fsDep, prompter, dsFactory) {
|
|
|
87
109
|
const envContent = (0, env_1.buildEnvContent)({
|
|
88
110
|
...existingEnv,
|
|
89
111
|
SCHEDULER_ENABLED: answers.schedulerEnabled ? 'true' : 'false',
|
|
112
|
+
LOG_ROTATION_MAX_SIZE_MB: String(logMaxSizeMb),
|
|
113
|
+
LOG_ROTATION_MAX_FILES: String(logMaxFiles),
|
|
90
114
|
}, {
|
|
91
115
|
host: answers.host,
|
|
92
116
|
port: answers.port,
|
|
@@ -4,6 +4,7 @@ exports.validatePort = validatePort;
|
|
|
4
4
|
exports.isValidPostgresConnectionString = isValidPostgresConnectionString;
|
|
5
5
|
exports.collectProviders = collectProviders;
|
|
6
6
|
exports.normalizeProviders = normalizeProviders;
|
|
7
|
+
exports.parsePositiveInt = parsePositiveInt;
|
|
7
8
|
const types_1 = require("../types");
|
|
8
9
|
function validatePort(port) {
|
|
9
10
|
const parsedPort = Number(port);
|
|
@@ -48,3 +49,16 @@ function normalizeProviders(values = []) {
|
|
|
48
49
|
throw new Error(errors.join('\n'));
|
|
49
50
|
return result;
|
|
50
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Parses a string as a positive integer.
|
|
54
|
+
* Returns the integer when the value is a strict positive integer string,
|
|
55
|
+
* or `undefined` when the input is `undefined`, a decimal, or non-numeric.
|
|
56
|
+
*/
|
|
57
|
+
function parsePositiveInt(value) {
|
|
58
|
+
if (value === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
if (!/^[1-9]\d*$/.test(value)) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return Number(value);
|
|
64
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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.convertOpenApiToPostman = convertOpenApiToPostman;
|
|
37
|
+
exports.writePostmanCollection = writePostmanCollection;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
function convertOpenApiToPostman(openApiJson, convert) {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
convert({ type: 'string', data: openApiJson }, { schemaFaker: true }, (error, result) => {
|
|
42
|
+
if (error) {
|
|
43
|
+
reject(error instanceof Error ? error : new Error('Converter failed'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!result?.result) {
|
|
47
|
+
reject(new Error(result?.reason ??
|
|
48
|
+
'Could not convert OpenAPI document to Postman collection'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
resolve(result.output?.[0]?.data ?? {});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function writePostmanCollection(outputPath, collection) {
|
|
56
|
+
fs.writeFileSync(outputPath, JSON.stringify(collection, null, 2));
|
|
57
|
+
}
|
|
@@ -53,4 +53,10 @@ exports.envValidationSchema = Joi.object({
|
|
|
53
53
|
.default('development'),
|
|
54
54
|
ALLOWED_ORIGINS: Joi.string().optional(),
|
|
55
55
|
SCHEDULER_ENABLED: Joi.boolean().default(true),
|
|
56
|
+
LOG_ROTATION_MAX_SIZE_MB: Joi.string()
|
|
57
|
+
.pattern(/^[1-9]\d*$/)
|
|
58
|
+
.optional(),
|
|
59
|
+
LOG_ROTATION_MAX_FILES: Joi.string()
|
|
60
|
+
.pattern(/^[1-9]\d*$/)
|
|
61
|
+
.optional(),
|
|
56
62
|
});
|
|
@@ -0,0 +1,214 @@
|
|
|
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.RotatingFileLogger = exports.DEFAULT_MAX_FILES = exports.DEFAULT_MAX_SIZE_MB = exports.LOG_FILENAME = void 0;
|
|
37
|
+
exports.shouldEnableFileLogging = shouldEnableFileLogging;
|
|
38
|
+
exports.getLogRotationOptions = getLogRotationOptions;
|
|
39
|
+
exports.persistRuntimeLoggerInitFailure = persistRuntimeLoggerInitFailure;
|
|
40
|
+
exports.initRuntimeLogger = initRuntimeLogger;
|
|
41
|
+
exports.teardownRuntimeLogger = teardownRuntimeLogger;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
exports.LOG_FILENAME = 'server.log';
|
|
46
|
+
exports.DEFAULT_MAX_SIZE_MB = 10;
|
|
47
|
+
exports.DEFAULT_MAX_FILES = 4;
|
|
48
|
+
const ARCHIVE_PREFIX = 'server-';
|
|
49
|
+
function parseStrictPositiveInt(value, envName) {
|
|
50
|
+
if (!/^[1-9]\d*$/.test(value)) {
|
|
51
|
+
throw new Error(`Invalid ${envName}: "${value}". Must be a plain positive integer (e.g. 10).`);
|
|
52
|
+
}
|
|
53
|
+
const n = Number(value);
|
|
54
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
55
|
+
throw new Error(`Invalid ${envName}: "${value}". Must be a positive integer >= 1.`);
|
|
56
|
+
}
|
|
57
|
+
return n;
|
|
58
|
+
}
|
|
59
|
+
function shouldEnableFileLogging() {
|
|
60
|
+
if (process.env.AGENT_ORCHESTRATOR_HOME)
|
|
61
|
+
return true;
|
|
62
|
+
if (process.env.LOG_ROTATION_MAX_SIZE_MB !== undefined ||
|
|
63
|
+
process.env.LOG_ROTATION_MAX_FILES !== undefined)
|
|
64
|
+
return true;
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function getLogRotationOptions() {
|
|
68
|
+
if (!shouldEnableFileLogging())
|
|
69
|
+
return null;
|
|
70
|
+
const logDir = process.env.AGENT_ORCHESTRATOR_HOME || os.tmpdir();
|
|
71
|
+
const maxSizeMb = process.env.LOG_ROTATION_MAX_SIZE_MB !== undefined
|
|
72
|
+
? parseStrictPositiveInt(process.env.LOG_ROTATION_MAX_SIZE_MB, 'LOG_ROTATION_MAX_SIZE_MB')
|
|
73
|
+
: exports.DEFAULT_MAX_SIZE_MB;
|
|
74
|
+
const maxFiles = process.env.LOG_ROTATION_MAX_FILES !== undefined
|
|
75
|
+
? parseStrictPositiveInt(process.env.LOG_ROTATION_MAX_FILES, 'LOG_ROTATION_MAX_FILES')
|
|
76
|
+
: exports.DEFAULT_MAX_FILES;
|
|
77
|
+
return { logDir, maxSizeMb, maxFiles };
|
|
78
|
+
}
|
|
79
|
+
function persistRuntimeLoggerInitFailure(message, fsDep = fs) {
|
|
80
|
+
if (!shouldEnableFileLogging()) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const logDir = process.env.AGENT_ORCHESTRATOR_HOME || os.tmpdir();
|
|
84
|
+
fsDep.mkdirSync(logDir, { recursive: true, mode: 0o700 });
|
|
85
|
+
const logFilePath = path.join(logDir, exports.LOG_FILENAME);
|
|
86
|
+
fsDep.appendFileSync(logFilePath, `[preload] Runtime logger initialization failed: ${message}\n`);
|
|
87
|
+
return logFilePath;
|
|
88
|
+
}
|
|
89
|
+
class RotatingFileLogger {
|
|
90
|
+
logFile;
|
|
91
|
+
maxSizeBytes;
|
|
92
|
+
maxFiles;
|
|
93
|
+
fsDep;
|
|
94
|
+
getNow;
|
|
95
|
+
originalStdoutWrite = null;
|
|
96
|
+
originalStderrWrite = null;
|
|
97
|
+
active = false;
|
|
98
|
+
constructor(options) {
|
|
99
|
+
this.logFile = path.join(options.logDir, exports.LOG_FILENAME);
|
|
100
|
+
this.maxSizeBytes = options.maxSizeMb * 1024 * 1024;
|
|
101
|
+
this.maxFiles = options.maxFiles;
|
|
102
|
+
this.fsDep = options.fsDep ?? fs;
|
|
103
|
+
this.getNow = options.getNow ?? (() => new Date());
|
|
104
|
+
}
|
|
105
|
+
get logFilePath() {
|
|
106
|
+
return this.logFile;
|
|
107
|
+
}
|
|
108
|
+
init() {
|
|
109
|
+
if (this.active)
|
|
110
|
+
return;
|
|
111
|
+
const dir = path.dirname(this.logFile);
|
|
112
|
+
if (!this.fsDep.existsSync(dir)) {
|
|
113
|
+
this.fsDep.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
114
|
+
}
|
|
115
|
+
this.originalStdoutWrite = process.stdout.write;
|
|
116
|
+
this.originalStderrWrite = process.stderr.write;
|
|
117
|
+
process.stdout.write = makeTeePatch(this.originalStdoutWrite, (chunk) => this.writeToFile(chunk));
|
|
118
|
+
process.stderr.write = makeTeePatch(this.originalStderrWrite, (chunk) => this.writeToFile(chunk));
|
|
119
|
+
this.active = true;
|
|
120
|
+
}
|
|
121
|
+
writeToFile(chunk) {
|
|
122
|
+
try {
|
|
123
|
+
const incomingBytes = typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.byteLength;
|
|
124
|
+
this.rotateIfNeeded(incomingBytes);
|
|
125
|
+
this.fsDep.appendFileSync(this.logFile, chunk);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
rotateIfNeeded(incomingBytes = 0) {
|
|
131
|
+
try {
|
|
132
|
+
if (!this.fsDep.existsSync(this.logFile))
|
|
133
|
+
return;
|
|
134
|
+
const stat = this.fsDep.statSync(this.logFile);
|
|
135
|
+
if (stat.size + incomingBytes < this.maxSizeBytes)
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const ts = this.getNow().toISOString().replace(/[:.]/g, '-');
|
|
142
|
+
const dir = path.dirname(this.logFile);
|
|
143
|
+
const rotated = path.join(dir, `${ARCHIVE_PREFIX}${ts}.log`);
|
|
144
|
+
try {
|
|
145
|
+
this.fsDep.renameSync(this.logFile, rotated);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.pruneOldArchives();
|
|
151
|
+
}
|
|
152
|
+
pruneOldArchives() {
|
|
153
|
+
const dir = path.dirname(this.logFile);
|
|
154
|
+
let archives;
|
|
155
|
+
try {
|
|
156
|
+
archives = this.fsDep
|
|
157
|
+
.readdirSync(dir)
|
|
158
|
+
.filter((f) => f.startsWith(ARCHIVE_PREFIX) &&
|
|
159
|
+
f.endsWith('.log') &&
|
|
160
|
+
f !== exports.LOG_FILENAME)
|
|
161
|
+
.sort();
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
while (archives.length > this.maxFiles) {
|
|
167
|
+
const oldest = archives.shift();
|
|
168
|
+
try {
|
|
169
|
+
this.fsDep.unlinkSync(path.join(dir, oldest));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
teardown() {
|
|
176
|
+
if (!this.active)
|
|
177
|
+
return;
|
|
178
|
+
if (this.originalStdoutWrite) {
|
|
179
|
+
process.stdout.write = this.originalStdoutWrite;
|
|
180
|
+
}
|
|
181
|
+
if (this.originalStderrWrite) {
|
|
182
|
+
process.stderr.write = this.originalStderrWrite;
|
|
183
|
+
}
|
|
184
|
+
this.active = false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.RotatingFileLogger = RotatingFileLogger;
|
|
188
|
+
function makeTeePatch(original, writeToFile) {
|
|
189
|
+
const orig = original;
|
|
190
|
+
return function (chunk, encodingOrCb, cb) {
|
|
191
|
+
writeToFile(chunk);
|
|
192
|
+
if (typeof encodingOrCb === 'function') {
|
|
193
|
+
return orig.call(this, chunk, encodingOrCb);
|
|
194
|
+
}
|
|
195
|
+
return orig.call(this, chunk, encodingOrCb, cb);
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
let activeLogger = null;
|
|
199
|
+
function initRuntimeLogger() {
|
|
200
|
+
if (activeLogger)
|
|
201
|
+
return activeLogger;
|
|
202
|
+
const opts = getLogRotationOptions();
|
|
203
|
+
if (!opts)
|
|
204
|
+
return null;
|
|
205
|
+
activeLogger = new RotatingFileLogger(opts);
|
|
206
|
+
activeLogger.init();
|
|
207
|
+
return activeLogger;
|
|
208
|
+
}
|
|
209
|
+
function teardownRuntimeLogger() {
|
|
210
|
+
if (activeLogger) {
|
|
211
|
+
activeLogger.teardown();
|
|
212
|
+
activeLogger = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -15,6 +15,7 @@ const migration_state_1 = require("./database/migration-state");
|
|
|
15
15
|
const port_defaults_1 = require("./config/port.defaults");
|
|
16
16
|
const host_defaults_1 = require("./config/host.defaults");
|
|
17
17
|
const runtime_paths_1 = require("./config/runtime-paths");
|
|
18
|
+
const runtime_logger_1 = require("./config/runtime-logger");
|
|
18
19
|
const logger = new common_1.Logger('Bootstrap');
|
|
19
20
|
(0, runtime_paths_1.loadRuntimeEnv)();
|
|
20
21
|
async function ensureDatabaseIsReadyForStartup() {
|
|
@@ -38,6 +39,13 @@ async function ensureDatabaseIsReadyForStartup() {
|
|
|
38
39
|
].join(' '));
|
|
39
40
|
}
|
|
40
41
|
async function bootstrap() {
|
|
42
|
+
try {
|
|
43
|
+
(0, runtime_logger_1.initRuntimeLogger)();
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
(0, runtime_logger_1.persistRuntimeLoggerInitFailure)(String(err));
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
41
49
|
await ensureDatabaseIsReadyForStartup();
|
|
42
50
|
const nodeEnv = process.env.NODE_ENV || 'development';
|
|
43
51
|
const defaultLevels = nodeEnv === 'production'
|
|
@@ -103,11 +103,10 @@ let RecurrentTaskSchedulerService = RecurrentTaskSchedulerService_1 = class Recu
|
|
|
103
103
|
if (name.startsWith('recurrent-task-')) {
|
|
104
104
|
const taskId = name.replace('recurrent-task-', '');
|
|
105
105
|
const task = activeTasks.find((t) => t.id === taskId);
|
|
106
|
-
const
|
|
106
|
+
const jobIsInactive = !job.isActive;
|
|
107
107
|
if (!activeTaskIds.has(taskId) ||
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
jobWithCron.cronTime.source !== task.cronExpression)) {
|
|
108
|
+
jobIsInactive ||
|
|
109
|
+
(task && job.cronTime && job.cronTime.source !== task.cronExpression)) {
|
|
111
110
|
void job.stop();
|
|
112
111
|
this.schedulerRegistry.deleteCronJob(name);
|
|
113
112
|
}
|