@bpinhosilva/agent-orchestrator 1.0.0-alpha.40 → 1.0.0-alpha.42

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 (149) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +69 -11
  3. package/dist/auth/auth.controller.js +1 -0
  4. package/dist/auth/auth.service.js +10 -5
  5. package/dist/auth/entities/refresh-token.entity.js +6 -18
  6. package/dist/cli/commands/config.command.js +47 -0
  7. package/dist/cli/commands/health.command.js +50 -0
  8. package/dist/cli/commands/index.js +10 -0
  9. package/dist/cli/commands/logs.command.js +9 -1
  10. package/dist/cli/commands/migrate.command.js +2 -2
  11. package/dist/cli/commands/reset-password.command.js +138 -0
  12. package/dist/cli/commands/restart.command.js +29 -18
  13. package/dist/cli/commands/rotate-secrets.command.js +120 -0
  14. package/dist/cli/commands/run.command.js +39 -34
  15. package/dist/cli/commands/seed-admin.command.js +25 -0
  16. package/dist/cli/commands/status.command.js +25 -2
  17. package/dist/cli/commands/stop.command.js +12 -6
  18. package/dist/cli/env.js +26 -2
  19. package/dist/cli/health.js +98 -0
  20. package/dist/cli/process-manager.js +97 -47
  21. package/dist/cli/setup/admin.js +1 -0
  22. package/dist/cli/setup/index.js +25 -6
  23. package/dist/config/typeorm.js +2 -4
  24. package/dist/main.js +1 -1
  25. package/dist/migrations/1775698253996-AddArtifactsToRecurrentTaskExecs.js +99 -84
  26. package/dist/migrations/1775938708731-ConvertIdsToUuid.js +1 -0
  27. package/dist/migrations/1776390163236-AddMissingIndexes.js +124 -0
  28. package/dist/migrations/1776400000000-ProductionHardening.js +119 -0
  29. package/dist/projects/dto/create-project.dto.js +3 -1
  30. package/dist/projects/entities/project-member.entity.js +2 -1
  31. package/dist/projects/projects.service.js +1 -1
  32. package/dist/providers/dto/create-provider.dto.js +3 -1
  33. package/dist/tasks/entities/recurrent-task-exec.entity.js +2 -1
  34. package/dist/tasks/entities/recurrent-task.entity.js +6 -5
  35. package/dist/tasks/recurrent-tasks.service.js +2 -2
  36. package/dist/ui/assets/AgentFleet-BarfEwcK.js +1 -0
  37. package/dist/ui/assets/AppErrorBoundary-BwnK_K-O.js +1 -0
  38. package/dist/ui/assets/{AttachmentItem-C-dVDZzk.js → AttachmentItem-Cerhbyya.js} +1 -1
  39. package/dist/ui/assets/AuthContextInstance-DiFo9Qb2.js +1 -0
  40. package/dist/ui/assets/ConfirmDialog-y3vTcqFR.js +1 -0
  41. package/dist/ui/assets/CreateRecurrentTaskModal-BgfnJ1n8.js +1 -0
  42. package/dist/ui/assets/CreateTaskModal-BH9lOLYT.js +1 -0
  43. package/dist/ui/assets/ExecLogModal-ShacCOOV.js +1 -0
  44. package/dist/ui/assets/{MarkdownField-CijtVjB5.js → MarkdownField--1gpyapw.js} +1 -1
  45. package/dist/ui/assets/Profile-qnuRN5Qv.js +1 -0
  46. package/dist/ui/assets/ProjectDetail-ZYQG9yn2.js +1 -0
  47. package/dist/ui/assets/Providers-DR7srJHq.js +1 -0
  48. package/dist/ui/assets/Scheduler-Bs3DC0re.js +2 -0
  49. package/dist/ui/assets/Settings-C3ad44vP.js +1 -0
  50. package/dist/ui/assets/TaskDetail-CyKAF8lf.js +1 -0
  51. package/dist/ui/assets/TaskExecutions-BeodRIz1.js +3 -0
  52. package/dist/ui/assets/TaskManager-BA2Y31ut.js +9 -0
  53. package/dist/ui/assets/UserAvatar-Z5W8S1dG.js +1 -0
  54. package/dist/ui/assets/UserDetail-BvWm-U4y.js +1 -0
  55. package/dist/ui/assets/Users-CQNcXLyV.js +1 -0
  56. package/dist/ui/assets/{activity-D2aBFbnN.js → activity-CmAajKmR.js} +1 -1
  57. package/dist/ui/assets/agents-b8btewki.js +1 -0
  58. package/dist/ui/assets/auth-dROenHXk.js +1 -0
  59. package/dist/ui/assets/bot-QVmnxPf4.js +1 -0
  60. package/dist/ui/assets/{box-3f35ZKNV.js → box-Bw_pyYzU.js} +1 -1
  61. package/dist/ui/assets/{brain-DwFWAhZ9.js → brain-C6vlLcg3.js} +1 -1
  62. package/dist/ui/assets/briefcase-DtHlat45.js +1 -0
  63. package/dist/ui/assets/check-DTei8Qlg.js +1 -0
  64. package/dist/ui/assets/chevron-down-LTeQHW9O.js +1 -0
  65. package/dist/ui/assets/chevron-left-CJc_eQid.js +1 -0
  66. package/dist/ui/assets/chevron-right-G5-HRo_C.js +1 -0
  67. package/dist/ui/assets/circle-alert-pUx6yhcF.js +1 -0
  68. package/dist/ui/assets/circle-check-B9kyRki5.js +1 -0
  69. package/dist/ui/assets/{client-CylGrWpP.js → client-BGOBXkO8.js} +9 -6
  70. package/dist/ui/assets/clock-BY4rrypg.js +1 -0
  71. package/dist/ui/assets/cn-CWOQtFh4.js +1 -0
  72. package/dist/ui/assets/{cpu-BN5F1CHN.js → cpu-8Sbc9Dk0.js} +1 -1
  73. package/dist/ui/assets/{database-HQ8maqdI.js → database-D6O4hvbm.js} +1 -1
  74. package/dist/ui/assets/{download-BVJ99Xi2.js → download-DHcd5oLD.js} +1 -1
  75. package/dist/ui/assets/{eye-CSLoB6-a.js → eye-Cc-vy4Zu.js} +1 -1
  76. package/dist/ui/assets/{file-text-CRyDRJx0.js → file-text-DWBSXx5l.js} +1 -1
  77. package/dist/ui/assets/index-D6skFXwB.css +2 -0
  78. package/dist/ui/assets/index-VNAG8cJ1.js +3 -0
  79. package/dist/ui/assets/info-1jA6X-_e.js +1 -0
  80. package/dist/ui/assets/{layers-BiK6YtWR.js → layers-BcHXXg-4.js} +1 -1
  81. package/dist/ui/assets/loader-circle-Cl6yIkPK.js +1 -0
  82. package/dist/ui/assets/panels-top-left-Vk8FzAxf.js +1 -0
  83. package/dist/ui/assets/{paperclip-THy_ev9U.js → paperclip-DWJjaP8B.js} +1 -1
  84. package/dist/ui/assets/plus-Dx6G8SOZ.js +1 -0
  85. package/dist/ui/assets/projects-CUOthD8N.js +1 -0
  86. package/dist/ui/assets/{providers-DGytjnDB.js → providers-CNrSTcdc.js} +1 -1
  87. package/dist/ui/assets/recurrent-tasks-CKT47N2l.js +1 -0
  88. package/dist/ui/assets/{refresh-cw-BGkg-lCf.js → refresh-cw-DQW6jR7M.js} +1 -1
  89. package/dist/ui/assets/{rocket-DzN1Mizs.js → rocket-CMSwBl_C.js} +1 -1
  90. package/dist/ui/assets/{save-zLR2Bpx5.js → save-DycJmlX0.js} +1 -1
  91. package/dist/ui/assets/{send-Bwuzypop.js → send-BZjwSrJW.js} +1 -1
  92. package/dist/ui/assets/server-CJE2K1Vt.js +1 -0
  93. package/dist/ui/assets/settings-at7JqFrc.js +1 -0
  94. package/dist/ui/assets/{shield-alert-BRwAB12k.js → shield-alert-CP5GVXxa.js} +1 -1
  95. package/dist/ui/assets/{shield-check-CdGbbgI2.js → shield-check-Cr4SHjdR.js} +1 -1
  96. package/dist/ui/assets/{sparkles-Cw1RdUld.js → sparkles-v57Nc-z-.js} +1 -1
  97. package/dist/ui/assets/{taskFormSchemas-mRaYZNuY.js → taskFormSchemas-dl1t1OyX.js} +1 -1
  98. package/dist/ui/assets/{tasks-CaT1ysud.js → tasks-DEUQCNoH.js} +1 -1
  99. package/dist/ui/assets/{terminal-DXcWSHx9.js → terminal-a6AV2mPO.js} +1 -1
  100. package/dist/ui/assets/{trash-2-BlARVDmE.js → trash-2-DJpTXgEP.js} +1 -1
  101. package/dist/ui/assets/{trending-up-B76ihhdP.js → trending-up-DlrXEXE6.js} +1 -1
  102. package/dist/ui/assets/useNotification-DQayTSUL.js +1 -0
  103. package/dist/ui/assets/{usePersistentFlag-DSeFEXMm.js → usePersistentFlag-R3_SXL_2.js} +1 -1
  104. package/dist/ui/assets/useProject-DhK9Ze6F.js +1 -0
  105. package/dist/ui/assets/user--KOoEB9m.js +1 -0
  106. package/dist/ui/assets/{user-plus-CiJgTJ8j.js → user-plus-nDkwsBT1.js} +1 -1
  107. package/dist/ui/assets/{users-D8u7T4bA.js → users-C6WiDiuN.js} +1 -1
  108. package/dist/ui/assets/users-Ef6Sh2iR.js +1 -0
  109. package/dist/ui/assets/vendor-dnd-CfaHPvi0.js +5 -0
  110. package/dist/ui/assets/{vendor-forms-BmyvqYDG.js → vendor-forms-DHyqHeyd.js} +1 -1
  111. package/dist/ui/assets/{vendor-markdown-Dl_1qnne.js → vendor-markdown-DoJbQ1of.js} +10 -10
  112. package/dist/ui/assets/vendor-motion-CMGWJcqR.js +9 -0
  113. package/dist/ui/assets/{vendor-query-BMPnNmZi.js → vendor-query-xpDrc4rM.js} +1 -1
  114. package/dist/ui/assets/{vendor-react-CiDbU5Ns.js → vendor-react-BmVaKUwY.js} +3 -3
  115. package/dist/ui/assets/x-wDy15QMx.js +1 -0
  116. package/dist/ui/assets/{zap-BI5M4WZX.js → zap-BmhZqgvm.js} +1 -1
  117. package/dist/ui/index.html +28 -9
  118. package/dist/users/dto/create-user.dto.js +1 -0
  119. package/dist/users/entities/user.entity.js +2 -1
  120. package/package.json +1 -1
  121. package/dist/ui/assets/AgentFleet-KWtvV65G.js +0 -1
  122. package/dist/ui/assets/ConfirmDialog-K_zBOzgz.js +0 -1
  123. package/dist/ui/assets/CreateRecurrentTaskModal-DoCnygQ_.js +0 -1
  124. package/dist/ui/assets/CreateTaskModal-CwqWIjtn.js +0 -1
  125. package/dist/ui/assets/ExecLogModal-DMde_Nmp.js +0 -1
  126. package/dist/ui/assets/Profile-BF_0uqTD.js +0 -1
  127. package/dist/ui/assets/ProjectDetail-DxSwFBLV.js +0 -1
  128. package/dist/ui/assets/Providers-Dvgpa-Of.js +0 -1
  129. package/dist/ui/assets/Scheduler-wffCLek8.js +0 -2
  130. package/dist/ui/assets/Settings-hEm8leNX.js +0 -1
  131. package/dist/ui/assets/TaskDetail-oOyTrEgR.js +0 -1
  132. package/dist/ui/assets/TaskExecutions-C254Hpwn.js +0 -3
  133. package/dist/ui/assets/TaskManager-LfSDtUb0.js +0 -9
  134. package/dist/ui/assets/UserDetail-oSfzMgTV.js +0 -1
  135. package/dist/ui/assets/Users-lYJybTKR.js +0 -1
  136. package/dist/ui/assets/check-BhOeS9mA.js +0 -1
  137. package/dist/ui/assets/chevron-down-DOfOMDZp.js +0 -1
  138. package/dist/ui/assets/chevron-left-QkqjdeR4.js +0 -1
  139. package/dist/ui/assets/chevron-right-KmgHEojr.js +0 -1
  140. package/dist/ui/assets/clock-BTNXfvPT.js +0 -1
  141. package/dist/ui/assets/cn-D-eQBQBv.js +0 -1
  142. package/dist/ui/assets/index-2EhUaHN_.js +0 -3
  143. package/dist/ui/assets/index-gxaIk1id.css +0 -2
  144. package/dist/ui/assets/loader-circle-BXAv24hD.js +0 -1
  145. package/dist/ui/assets/recurrent-tasks-DZBdtlAy.js +0 -1
  146. package/dist/ui/assets/user-DpMk7aqI.js +0 -1
  147. package/dist/ui/assets/vendor-dnd-CxfOy4-Z.js +0 -5
  148. package/dist/ui/assets/vendor-motion-CPra8At-.js +0 -9
  149. /package/dist/ui/assets/{agentEmojis-CEz5pgbJ.js → agentEmojis-BQA0jC3z.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [1.0.0-alpha.42](https://github.com/bpinhosilva/agent-orchestrator/compare/v1.0.0-alpha.41...v1.0.0-alpha.42) (2026-04-17)
2
+
3
+
4
+ ### Features
5
+
6
+ * add early crash detection and log tailing for server process ([b3c7945](https://github.com/bpinhosilva/agent-orchestrator/commit/b3c79454f030845f3056e30f9daab1a7726ce00e))
7
+
8
+ # [1.0.0-alpha.41](https://github.com/bpinhosilva/agent-orchestrator/compare/v1.0.0-alpha.40...v1.0.0-alpha.41) (2026-04-17)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * update collisionDetection to return an empty array in TaskManager tests ([b64158e](https://github.com/bpinhosilva/agent-orchestrator/commit/b64158e61c76a0d148900d36cb9f05784e5d5461))
14
+
1
15
  # [1.0.0-alpha.40](https://github.com/bpinhosilva/agent-orchestrator/compare/v1.0.0-alpha.39...v1.0.0-alpha.40) (2026-04-17)
2
16
 
3
17
 
package/README.md CHANGED
@@ -26,7 +26,7 @@ Agent Orchestrator is an open-source platform for managing AI agents, tasks, and
26
26
  - Project management with project membership and RBAC
27
27
  - Task execution plus recurring scheduling
28
28
  - File upload and artifact-backed task workflows
29
- - Packaged CLI/runtime for setup, run, status, logs, stop, and migrate
29
+ - Packaged CLI/runtime with full lifecycle management: `setup`, `run`, `restart`, `stop`, `status`, `health`, `logs`, `migrate`, `config`, `reset-password`, and `rotate-secrets`
30
30
  - React dashboard served by the backend or packaged runtime
31
31
 
32
32
  ## Planned direction
@@ -71,6 +71,7 @@ agent-orchestrator setup
71
71
  agent-orchestrator run
72
72
  agent-orchestrator restart
73
73
  agent-orchestrator status
74
+ agent-orchestrator health
74
75
  ```
75
76
 
76
77
  `setup` can create the runtime `.env`, run migrations, seed an admin user, and prompt you to apply pending migrations after package updates. `run` does not upgrade the database automatically. The default runtime home is `~/.agent-orchestrator`, or `${AGENT_ORCHESTRATOR_HOME}` if you set it explicitly.
@@ -83,7 +84,7 @@ For deeper CLI usage, see [docs/CLI.md](docs/CLI.md).
83
84
  git clone https://github.com/bpinhosilva/agent-orchestrator.git
84
85
  cd agent-orchestrator
85
86
  npm install
86
- npm rebuild
87
+ npm rebuild --ignore-scripts=false
87
88
  npm run build:all
88
89
  ```
89
90
 
@@ -142,6 +143,15 @@ SQLite is the default local/runtime option when `DATABASE_URL` is not set. The d
142
143
  - `local.sqlite` in the project/package root, or
143
144
  - `${AGENT_ORCHESTRATOR_HOME}/local.sqlite` when runtime home is set
144
145
 
146
+ > **Important — dev server vs. packaged CLI runtime use different databases by default.**
147
+ > Running `npm run dev` or `npm run start:dev` uses `./local.sqlite` in the project root.
148
+ > Running `node dist/cli/index.js` (or the installed `agent-orchestrator` binary) defaults to `~/.agent-orchestrator/local.sqlite`.
149
+ > If you run the dev server and also use CLI admin commands (e.g. `reset-password`, `migrate`), point the CLI at the project root database:
150
+ >
151
+ > ```bash
152
+ > AGENT_ORCHESTRATOR_HOME=/path/to/agent-orchestrator node dist/cli/index.js reset-password
153
+ > ```
154
+
145
155
  ### PostgreSQL
146
156
 
147
157
  Use PostgreSQL by setting `DATABASE_URL` or `DB_TYPE=postgres`:
@@ -195,18 +205,21 @@ npm run start:dev
195
205
  agent-orchestrator setup
196
206
  agent-orchestrator run
197
207
  agent-orchestrator status
208
+ agent-orchestrator health
198
209
  agent-orchestrator logs --lines 50
199
210
  agent-orchestrator restart
200
211
  agent-orchestrator stop
212
+ agent-orchestrator config show
213
+ agent-orchestrator rotate-secrets
201
214
  ```
202
215
 
203
216
  When running the packaged app or a production build with static UI enabled, the dashboard is served from `http://localhost:15789` by default.
204
217
 
205
218
  ## Docker
206
219
 
207
- The repository ships three Compose entrypoints:
220
+ > For the full Docker guide, see [docs/DOCKER.md](docs/DOCKER.md).
208
221
 
209
- All Compose stacks now require the database variables in the project `.env` file: `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, and `POSTGRES_TEST_DB` for the integration stack.
222
+ The repository ships three Compose entrypoints:
210
223
 
211
224
  | File | Purpose |
212
225
  | --- | --- |
@@ -216,15 +229,56 @@ All Compose stacks now require the database variables in the project `.env` file
216
229
 
217
230
  ### Production-style stack
218
231
 
232
+ **Step 1: Create `.env`** — copy the example in the repo root and fill in your values:
233
+
219
234
  ```bash
220
- npm run docker:up
221
- docker compose run --rm api dist/cli/index.js migrate --yes
235
+ POSTGRES_USER=postgres
236
+ POSTGRES_PASSWORD=change_me
237
+ POSTGRES_DB=agent_orchestrator
238
+
239
+ JWT_SECRET=<at-least-32-char-secret>
240
+ JWT_REFRESH_SECRET=<at-least-32-char-secret>
241
+
242
+ # For seed-admin:
243
+ ADMIN_EMAIL=admin@example.com
244
+ ADMIN_PASSWORD=change_me
222
245
  ```
223
246
 
224
- Endpoints:
247
+ **Step 2: Run migrations**
248
+
249
+ ```bash
250
+ docker compose --profile tools run --rm migrate
251
+ ```
252
+
253
+ **Step 3: Seed the admin user** — credentials are read from `ADMIN_EMAIL` and `ADMIN_PASSWORD` in `.env`, never from CLI flags.
254
+
255
+ ```bash
256
+ docker compose --profile tools run --rm seed-admin
257
+ ```
258
+
259
+ **Step 4: Start the stack**
260
+
261
+ ```bash
262
+ docker compose up -d
263
+ ```
264
+
265
+ Access at `https://localhost` (your browser will warn about a self-signed cert — click through).
266
+
267
+ **Stopping:**
268
+
269
+ ```bash
270
+ docker compose down # stop, keep data
271
+ docker compose down -v # stop and wipe all data (including the PostgreSQL volume)
272
+ ```
273
+
274
+ **Custom domain:**
275
+
276
+ ```bash
277
+ DOMAIN=mysite.com
278
+ ALLOWED_ORIGINS=https://mysite.com
279
+ ```
225
280
 
226
- - UI: `https://localhost` or `https://agent-orchestrator.localhost`
227
- - API: `https://localhost/api/v1` or `https://agent-orchestrator.localhost/api/v1`
281
+ Caddy automatically provisions Let's Encrypt certificates for real public domains.
228
282
 
229
283
  In this stack the UI is served by **Caddy**, not by the Nest app. Docker explicitly sets `SERVE_STATIC_UI=false` so the backend only serves the API.
230
284
 
@@ -252,8 +306,8 @@ docker compose -f docker-compose.test.yml --profile tools run --rm cli
252
306
 
253
307
  Endpoints:
254
308
 
255
- - UI: `https://localhost:8444` or `https://agent-orchestrator.localhost:8444`
256
- - API: `https://localhost:8444/api/v1` or `https://agent-orchestrator.localhost:8444/api/v1`
309
+ - UI: `https://localhost:8444`
310
+ - API: `https://localhost:8444/api/v1`
257
311
 
258
312
  ## Development workflow
259
313
 
@@ -278,6 +332,7 @@ Endpoints:
278
332
 
279
333
  ## Useful docs
280
334
 
335
+ - [Docker guide](docs/DOCKER.md)
281
336
  - [CLI reference](docs/CLI.md)
282
337
  - [CI/CD pipeline](docs/CI_CD.md)
283
338
  - [Release process](docs/RELEASE.md)
@@ -290,6 +345,9 @@ Endpoints:
290
345
  - **Agent execution fails immediately**: confirm `GEMINI_API_KEY`, `ANTHROPIC_API_KEY`, or Ollama (`OLLAMA_HOST`) are set correctly for the provider in use
291
346
  - **Schema/startup issues**: run `npm run migration:run`
292
347
  - **Need to undo the latest migration**: run `npm run migration:revert`
348
+ - **Need to reset a user's password**: use `agent-orchestrator reset-password` — this also revokes all active sessions for that user. If the dev server (`npm run dev`) is running instead of the packaged runtime, the CLI targets a different database by default; override with `AGENT_ORCHESTRATOR_HOME=$(pwd) node dist/cli/index.js reset-password`
349
+ - **Need to rotate JWT secrets** (e.g. after a credential leak): use `agent-orchestrator rotate-secrets` — this regenerates `JWT_SECRET` and `JWT_REFRESH_SECRET`, invalidating all active sessions, and restarts the server automatically if it is running
350
+ - **Stale PostgreSQL volume (version mismatch)**: if the `db` container fails its health check with "data directory was initialized by PostgreSQL version X, which is not compatible with this version", run `docker compose down -v` to wipe the volume and start fresh
293
351
 
294
352
  ## License
295
353
 
@@ -153,6 +153,7 @@ __decorate([
153
153
  __metadata("design:returntype", void 0)
154
154
  ], AuthController.prototype, "getMe", null);
155
155
  __decorate([
156
+ (0, throttler_1.Throttle)({ default: { limit: 5, ttl: 60000 } }),
156
157
  (0, common_1.Patch)('me'),
157
158
  openapi.ApiResponse({ status: 200, type: Object }),
158
159
  __param(0, (0, common_1.Request)()),
@@ -44,6 +44,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
44
44
  var __param = (this && this.__param) || function (paramIndex, decorator) {
45
45
  return function (target, key) { decorator(target, key, paramIndex); }
46
46
  };
47
+ var AuthService_1;
47
48
  Object.defineProperty(exports, "__esModule", { value: true });
48
49
  exports.AuthService = void 0;
49
50
  const common_1 = require("@nestjs/common");
@@ -54,7 +55,7 @@ const typeorm_2 = require("@nestjs/typeorm");
54
55
  const users_service_1 = require("../users/users.service");
55
56
  const refresh_token_entity_1 = require("./entities/refresh-token.entity");
56
57
  const bcrypt = __importStar(require("bcrypt"));
57
- let AuthService = class AuthService {
58
+ let AuthService = AuthService_1 = class AuthService {
58
59
  usersService;
59
60
  jwtService;
60
61
  configService;
@@ -68,6 +69,7 @@ let AuthService = class AuthService {
68
69
  this.configService = configService;
69
70
  this.refreshTokenRepository = refreshTokenRepository;
70
71
  }
72
+ logger = new common_1.Logger(AuthService_1.name);
71
73
  async validateUser(userId) {
72
74
  try {
73
75
  const user = await this.usersService.findOne(userId);
@@ -75,7 +77,8 @@ let AuthService = class AuthService {
75
77
  return this.usersService.serializeUser(user);
76
78
  }
77
79
  }
78
- catch {
80
+ catch (error) {
81
+ this.logger.error('Failed to validate user', error instanceof Error ? error.stack : String(error));
79
82
  return null;
80
83
  }
81
84
  return null;
@@ -147,7 +150,8 @@ let AuthService = class AuthService {
147
150
  ? payload.sub
148
151
  : null;
149
152
  }
150
- catch {
153
+ catch (error) {
154
+ this.logger.warn('Failed to validate refresh token', error instanceof Error ? error.stack : String(error));
151
155
  return null;
152
156
  }
153
157
  }
@@ -254,12 +258,13 @@ let AuthService = class AuthService {
254
258
  }, { revokedAt: new Date() });
255
259
  }
256
260
  }
257
- catch {
261
+ catch (error) {
262
+ this.logger.warn('Failed to revoke refresh token (token may already be expired)', error instanceof Error ? error.message : String(error));
258
263
  }
259
264
  }
260
265
  };
261
266
  exports.AuthService = AuthService;
262
- exports.AuthService = AuthService = __decorate([
267
+ exports.AuthService = AuthService = AuthService_1 = __decorate([
263
268
  (0, common_1.Injectable)(),
264
269
  __param(3, (0, typeorm_2.InjectRepository)(refresh_token_entity_1.RefreshToken)),
265
270
  __metadata("design:paramtypes", [users_service_1.UsersService,
@@ -10,23 +10,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.RefreshToken = void 0;
13
- const openapi = require("@nestjs/swagger");
14
13
  const typeorm_1 = require("typeorm");
15
14
  const user_entity_1 = require("../../users/entities/user.entity");
16
15
  const typeorm_2 = require("../../config/typeorm");
17
16
  let RefreshToken = class RefreshToken {
18
- id;
19
- userId;
20
- user;
21
- token;
22
- issuedAt;
23
- expiresAt;
24
- absoluteExpiry;
25
- createdAt;
26
- revokedAt;
27
- static _OPENAPI_METADATA_FACTORY() {
28
- return { id: { required: true, type: () => String }, userId: { required: true, type: () => String }, user: { required: true, type: () => require("../../users/entities/user.entity").User }, token: { required: true, type: () => String }, issuedAt: { required: true, type: () => Date }, expiresAt: { required: true, type: () => Date }, absoluteExpiry: { required: true, type: () => Date }, createdAt: { required: true, type: () => Date }, revokedAt: { required: true, type: () => Date, nullable: true } };
29
- }
30
17
  };
31
18
  exports.RefreshToken = RefreshToken;
32
19
  __decorate([
@@ -51,11 +38,11 @@ __decorate([
51
38
  __metadata("design:type", Date)
52
39
  ], RefreshToken.prototype, "issuedAt", void 0);
53
40
  __decorate([
54
- (0, typeorm_1.Column)({ type: 'datetime' }),
41
+ (0, typeorm_1.Column)({ type: typeorm_2.DATETIME_COLUMN_TYPE }),
55
42
  __metadata("design:type", Date)
56
43
  ], RefreshToken.prototype, "expiresAt", void 0);
57
44
  __decorate([
58
- (0, typeorm_1.Column)({ type: 'datetime' }),
45
+ (0, typeorm_1.Column)({ type: typeorm_2.DATETIME_COLUMN_TYPE }),
59
46
  __metadata("design:type", Date)
60
47
  ], RefreshToken.prototype, "absoluteExpiry", void 0);
61
48
  __decorate([
@@ -63,11 +50,12 @@ __decorate([
63
50
  __metadata("design:type", Date)
64
51
  ], RefreshToken.prototype, "createdAt", void 0);
65
52
  __decorate([
66
- (0, typeorm_1.Column)({ type: 'datetime', nullable: true }),
67
- __metadata("design:type", Object)
53
+ (0, typeorm_1.Column)({ type: typeorm_2.DATETIME_COLUMN_TYPE, nullable: true }),
54
+ __metadata("design:type", Date)
68
55
  ], RefreshToken.prototype, "revokedAt", void 0);
69
56
  exports.RefreshToken = RefreshToken = __decorate([
70
57
  (0, typeorm_1.Entity)('refresh_tokens'),
71
58
  (0, typeorm_1.Index)(['userId', 'expiresAt']),
72
- (0, typeorm_1.Index)(['userId', 'revokedAt'])
59
+ (0, typeorm_1.Index)(['userId', 'revokedAt']),
60
+ (0, typeorm_1.Index)(['absoluteExpiry'])
73
61
  ], RefreshToken);
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerConfigCommand = registerConfigCommand;
4
+ const utils_1 = require("../utils");
5
+ const env_1 = require("../env");
6
+ const constants_1 = require("../constants");
7
+ /** Keys matching these patterns are masked unless --show-secrets is passed. */
8
+ const MASKED_KEY_PATTERN = /(_SECRET|_KEY)$/i;
9
+ const ALWAYS_MASKED_KEYS = new Set(['DATABASE_URL']);
10
+ function maskValue(key, value, showSecrets) {
11
+ if (showSecrets)
12
+ return value;
13
+ if (MASKED_KEY_PATTERN.test(key) || ALWAYS_MASKED_KEYS.has(key))
14
+ return '***';
15
+ return value;
16
+ }
17
+ function registerConfigCommand(program) {
18
+ const config = program
19
+ .command('config')
20
+ .description('Manage CLI runtime configuration');
21
+ config
22
+ .command('show')
23
+ .description('Display the current runtime configuration')
24
+ .option('--show-secrets', 'Reveal masked secret values (keys, tokens, URLs)')
25
+ .option('--format <format>', 'Output format: text or json', 'text')
26
+ .action((...args) => {
27
+ const opts = (0, utils_1.resolveActionOptions)(args);
28
+ const env = (0, env_1.readEnvFile)(constants_1.ENV_PATH);
29
+ if (Object.keys(env).length === 0) {
30
+ console.log(`No configuration found at ${constants_1.ENV_PATH}. Run "agent-orchestrator setup" first.`);
31
+ return;
32
+ }
33
+ const masked = Object.fromEntries(Object.entries(env).map(([k, v]) => [
34
+ k,
35
+ maskValue(k, v, opts.showSecrets ?? false),
36
+ ]));
37
+ if (opts.format === 'json') {
38
+ console.log(JSON.stringify(masked, null, 2));
39
+ }
40
+ else {
41
+ console.log(`Configuration from ${constants_1.ENV_PATH}:\n`);
42
+ for (const [key, value] of Object.entries(masked)) {
43
+ console.log(` ${key}=${value}`);
44
+ }
45
+ }
46
+ });
47
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerHealthCommand = registerHealthCommand;
4
+ const utils_1 = require("../utils");
5
+ const process_manager_1 = require("../process-manager");
6
+ const constants_1 = require("../constants");
7
+ const health_1 = require("../health");
8
+ function registerHealthCommand(program) {
9
+ program
10
+ .command('health')
11
+ .description('Check whether the orchestrator HTTP server is responding')
12
+ .option('--timeout <ms>', 'Request timeout in milliseconds', '5000')
13
+ .option('--format <format>', 'Output format: text or json', 'text')
14
+ .action(async (...args) => {
15
+ const opts = (0, utils_1.resolveActionOptions)(args);
16
+ const timeoutMs = Math.max(1, Number(opts.timeout ?? '5000') || 5000);
17
+ // Prefer metadata from the running process; fall back to .env config
18
+ const proc = (0, process_manager_1.findManagedProcess)();
19
+ const host = proc?.host ?? (0, process_manager_1.getConfiguredHost)(constants_1.ENV_PATH);
20
+ const port = proc?.port ?? (0, process_manager_1.getConfiguredPort)(constants_1.ENV_PATH);
21
+ const isRunning = proc !== null;
22
+ const result = await (0, health_1.httpHealthCheck)(host, port, timeoutMs);
23
+ if (opts.format === 'json') {
24
+ console.log(JSON.stringify({
25
+ running: isRunning,
26
+ healthy: result.healthy,
27
+ status: result.status ?? null,
28
+ host,
29
+ port,
30
+ error: result.error ?? null,
31
+ }));
32
+ }
33
+ else {
34
+ if (!isRunning) {
35
+ console.log('Orchestrator process is not running.');
36
+ }
37
+ else if (result.healthy) {
38
+ console.log(`Orchestrator is healthy (HTTP ${result.status}) at ${host}:${port}`);
39
+ }
40
+ else if (result.error) {
41
+ console.log(`Orchestrator is unreachable: ${result.error}`);
42
+ }
43
+ else {
44
+ console.log(`Orchestrator returned HTTP ${result.status ?? 'unknown'} at ${host}:${port}`);
45
+ }
46
+ }
47
+ if (!result.healthy)
48
+ process.exit(1);
49
+ });
50
+ }
@@ -8,6 +8,11 @@ const status_command_1 = require("./status.command");
8
8
  const logs_command_1 = require("./logs.command");
9
9
  const migrate_command_1 = require("./migrate.command");
10
10
  const restart_command_1 = require("./restart.command");
11
+ const health_command_1 = require("./health.command");
12
+ const config_command_1 = require("./config.command");
13
+ const reset_password_command_1 = require("./reset-password.command");
14
+ const rotate_secrets_command_1 = require("./rotate-secrets.command");
15
+ const seed_admin_command_1 = require("./seed-admin.command");
11
16
  function registerAllCommands(program) {
12
17
  (0, setup_command_1.registerSetupCommand)(program);
13
18
  (0, run_command_1.registerRunCommand)(program);
@@ -16,4 +21,9 @@ function registerAllCommands(program) {
16
21
  (0, status_command_1.registerStatusCommand)(program);
17
22
  (0, logs_command_1.registerLogsCommand)(program);
18
23
  (0, migrate_command_1.registerMigrateCommand)(program);
24
+ (0, health_command_1.registerHealthCommand)(program);
25
+ (0, config_command_1.registerConfigCommand)(program);
26
+ (0, reset_password_command_1.registerResetPasswordCommand)(program);
27
+ (0, rotate_secrets_command_1.registerRotateSecretsCommand)(program);
28
+ (0, seed_admin_command_1.registerSeedAdminCommand)(program);
19
29
  }
@@ -63,10 +63,18 @@ function registerLogsCommand(program) {
63
63
  console.log('Log file is empty.');
64
64
  }
65
65
  if (opts.follow) {
66
- let position = fs.statSync(constants_1.LOG_FILE).size;
66
+ const initialStat = fs.statSync(constants_1.LOG_FILE);
67
+ let position = initialStat.size;
68
+ let trackedIno = initialStat.ino;
67
69
  fs.watchFile(constants_1.LOG_FILE, { interval: 200 }, () => {
68
70
  try {
69
71
  const stat = fs.statSync(constants_1.LOG_FILE);
72
+ const rotated = stat.ino !== trackedIno || stat.size < position;
73
+ if (rotated) {
74
+ // File replaced or truncated — restart from beginning
75
+ position = 0;
76
+ trackedIno = stat.ino;
77
+ }
70
78
  if (stat.size > position) {
71
79
  const length = stat.size - position;
72
80
  const buffer = Buffer.alloc(length);
@@ -40,7 +40,7 @@ async function confirmAction(message, autoConfirm = false) {
40
40
  if (autoConfirm) {
41
41
  return true;
42
42
  }
43
- const enquirer = await Promise.resolve().then(() => __importStar(require('enquirer')));
43
+ const { default: enquirer } = await Promise.resolve().then(() => __importStar(require('enquirer')));
44
44
  const { confirmed } = await enquirer.prompt({
45
45
  type: 'confirm',
46
46
  name: 'confirmed',
@@ -53,7 +53,7 @@ async function promptForEnter(message, autoConfirm = false) {
53
53
  if (autoConfirm) {
54
54
  return;
55
55
  }
56
- const enquirer = await Promise.resolve().then(() => __importStar(require('enquirer')));
56
+ const { default: enquirer } = await Promise.resolve().then(() => __importStar(require('enquirer')));
57
57
  await enquirer.prompt({
58
58
  type: 'input',
59
59
  name: 'continue',
@@ -0,0 +1,138 @@
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.resetUserPassword = resetUserPassword;
37
+ exports.registerResetPasswordCommand = registerResetPasswordCommand;
38
+ const typeorm_1 = require("typeorm");
39
+ const utils_1 = require("../utils");
40
+ const typeorm_2 = require("../../config/typeorm");
41
+ const user_entity_1 = require("../../users/entities/user.entity");
42
+ const refresh_token_entity_1 = require("../../auth/entities/refresh-token.entity");
43
+ async function resetUserPassword(email, newPassword, factory = typeorm_2.createDataSource,
44
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
45
+ bcryptDep = require('bcrypt')) {
46
+ const dataSource = factory();
47
+ let initialized = false;
48
+ try {
49
+ await dataSource.initialize();
50
+ initialized = true;
51
+ const userRepository = dataSource.getRepository(user_entity_1.User);
52
+ const tokenRepository = dataSource.getRepository(refresh_token_entity_1.RefreshToken);
53
+ const user = await userRepository.findOne({ where: { email } });
54
+ if (!user) {
55
+ throw new Error(`User with email "${email}" not found.`);
56
+ }
57
+ const hashedPassword = await bcryptDep.hash(newPassword, 10);
58
+ await userRepository.update(user.id, { password: hashedPassword });
59
+ // Revoke all active (non-expired, non-revoked) refresh tokens so existing
60
+ // sessions cannot continue after a password reset.
61
+ await tokenRepository.update({ userId: user.id, revokedAt: (0, typeorm_1.IsNull)() }, { revokedAt: new Date() });
62
+ console.log(`Password updated for ${email}. All active sessions have been invalidated.`);
63
+ }
64
+ finally {
65
+ if (initialized) {
66
+ try {
67
+ await dataSource.destroy();
68
+ }
69
+ catch {
70
+ // ignore cleanup errors
71
+ }
72
+ }
73
+ }
74
+ }
75
+ function registerResetPasswordCommand(program, resetFn = resetUserPassword) {
76
+ program
77
+ .command('reset-password')
78
+ .description("Reset a user's password and revoke all their active sessions")
79
+ .option('--email <email>', 'Email address of the user')
80
+ .option('--password <password>', 'New password (min 8 characters) — prefer SETUP_ADMIN_PASSWORD env var')
81
+ .option('-y, --yes', 'Non-interactive mode (requires --email and --password or env var)')
82
+ .action(async (...args) => {
83
+ const opts = (0, utils_1.resolveActionOptions)(args);
84
+ if (opts.password) {
85
+ console.warn('Warning: Passing passwords as CLI flags exposes them in process tables and shell history. ' +
86
+ 'Use the SETUP_ADMIN_PASSWORD environment variable instead.');
87
+ }
88
+ let email;
89
+ let password;
90
+ const resolvedPassword = opts.password ?? process.env.SETUP_ADMIN_PASSWORD;
91
+ if (opts.yes) {
92
+ if (!opts.email || !resolvedPassword) {
93
+ console.error('--email and --password (or SETUP_ADMIN_PASSWORD env var) are required in non-interactive mode (--yes).');
94
+ process.exit(1);
95
+ return;
96
+ }
97
+ email = opts.email;
98
+ password = resolvedPassword;
99
+ }
100
+ else {
101
+ const { default: enquirer } = await Promise.resolve().then(() => __importStar(require('enquirer')));
102
+ const response = await enquirer.prompt([
103
+ {
104
+ type: 'input',
105
+ name: 'email',
106
+ message: 'User email:',
107
+ initial: opts.email ?? '',
108
+ },
109
+ {
110
+ type: 'password',
111
+ name: 'password',
112
+ message: 'New password (min 8 characters):',
113
+ validate: (v) => v.length >= 8 || 'Password must be at least 8 characters',
114
+ },
115
+ {
116
+ type: 'password',
117
+ name: 'confirm',
118
+ message: 'Confirm new password:',
119
+ validate: (v, state) => v === state?.answers?.password || 'Passwords do not match',
120
+ },
121
+ ]);
122
+ email = response.email;
123
+ password = response.password;
124
+ }
125
+ if (password.length < 8) {
126
+ console.error('Password must be at least 8 characters long.');
127
+ process.exit(1);
128
+ return;
129
+ }
130
+ try {
131
+ await resetFn(email, password);
132
+ }
133
+ catch (err) {
134
+ console.error(`Failed to reset password: ${err instanceof Error ? err.message : String(err)}`);
135
+ process.exit(1);
136
+ }
137
+ });
138
+ }
@@ -1,30 +1,41 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerRestartCommand = registerRestartCommand;
4
- const commander_1 = require("commander");
5
4
  const process_manager_1 = require("../process-manager");
6
- const run_command_1 = require("./run.command");
7
- const stop_command_1 = require("./stop.command");
5
+ const constants_1 = require("../constants");
8
6
  function registerRestartCommand(program) {
9
7
  program
10
8
  .command('restart')
11
9
  .description('Restart the orchestrator server (smart: stop if running, then start)')
12
10
  .action(async () => {
13
- const running = (0, process_manager_1.findManagedProcess)(); // TODO: pass default args if needed
14
- if (running) {
15
- // Stop if running
16
- await new Promise((resolve) => {
17
- const stopProgram = new commander_1.Command();
18
- (0, stop_command_1.registerStopCommand)(stopProgram);
19
- stopProgram.exitOverride();
20
- stopProgram.parse(['node', 'cli', 'stop'], { from: 'user' });
21
- setTimeout(resolve, 2000); // Wait for stop
22
- });
11
+ try {
12
+ const running = (0, process_manager_1.findManagedProcess)();
13
+ if (running) {
14
+ console.log(`Stopping Orchestrator (PID: ${running.pid})...`);
15
+ const died = await (0, process_manager_1.stopManagedProcessById)(running.pid, running.cwd, running.mainPath);
16
+ if (!died) {
17
+ console.error('Failed to stop orchestrator. Aborting restart to avoid duplicate instances.');
18
+ process.exit(1);
19
+ return;
20
+ }
21
+ (0, process_manager_1.removeRuntimeState)();
22
+ console.log('Orchestrator stopped.');
23
+ }
24
+ console.log('Starting Agent Orchestrator in background...');
25
+ const { pid, host, port } = (0, process_manager_1.startServer)();
26
+ console.log(`Orchestrator started in background.\n${(0, process_manager_1.formatProcessSummary)({
27
+ pid,
28
+ source: 'metadata',
29
+ cwd: constants_1.PACKAGE_ROOT,
30
+ mainPath: constants_1.MAIN_FILE,
31
+ host,
32
+ port,
33
+ })}`);
34
+ }
35
+ catch (err) {
36
+ const errorMessage = err instanceof Error ? err.message : String(err);
37
+ console.error(`Failed to restart orchestrator: ${errorMessage}`);
38
+ process.exit(1);
23
39
  }
24
- // Start
25
- const runProgram = new commander_1.Command();
26
- (0, run_command_1.registerRunCommand)(runProgram);
27
- runProgram.exitOverride();
28
- runProgram.parse(['node', 'cli', 'run'], { from: 'user' });
29
40
  });
30
41
  }