agentrix 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/README.md +235 -0
- package/bin/agentrix.js +5 -0
- package/dist/api/auth.d.ts +10 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +30 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/automation.d.ts +52 -0
- package/dist/api/automation.d.ts.map +1 -0
- package/dist/api/automation.js +181 -0
- package/dist/api/automation.js.map +1 -0
- package/dist/api/base-handler.d.ts +62 -0
- package/dist/api/base-handler.d.ts.map +1 -0
- package/dist/api/base-handler.js +55 -0
- package/dist/api/base-handler.js.map +1 -0
- package/dist/api/config.d.ts +5 -0
- package/dist/api/config.d.ts.map +1 -0
- package/dist/api/config.js +14 -0
- package/dist/api/config.js.map +1 -0
- package/dist/api/create-plan.d.ts +8 -0
- package/dist/api/create-plan.d.ts.map +1 -0
- package/dist/api/create-plan.js +77 -0
- package/dist/api/create-plan.js.map +1 -0
- package/dist/api/git-status.d.ts +6 -0
- package/dist/api/git-status.d.ts.map +1 -0
- package/dist/api/git-status.js +57 -0
- package/dist/api/git-status.js.map +1 -0
- package/dist/api/plans.d.ts +6 -0
- package/dist/api/plans.d.ts.map +1 -0
- package/dist/api/plans.js +75 -0
- package/dist/api/plans.js.map +1 -0
- package/dist/api/repo-dashboard.d.ts +13 -0
- package/dist/api/repo-dashboard.d.ts.map +1 -0
- package/dist/api/repo-dashboard.js +47 -0
- package/dist/api/repo-dashboard.js.map +1 -0
- package/dist/api/repo-issue.d.ts +12 -0
- package/dist/api/repo-issue.d.ts.map +1 -0
- package/dist/api/repo-issue.js +47 -0
- package/dist/api/repo-issue.js.map +1 -0
- package/dist/api/repos.d.ts +9 -0
- package/dist/api/repos.d.ts.map +1 -0
- package/dist/api/repos.js +46 -0
- package/dist/api/repos.js.map +1 -0
- package/dist/api/sessions.d.ts +5 -0
- package/dist/api/sessions.d.ts.map +1 -0
- package/dist/api/sessions.js +19 -0
- package/dist/api/sessions.js.map +1 -0
- package/dist/api/tasks.d.ts +6 -0
- package/dist/api/tasks.d.ts.map +1 -0
- package/dist/api/tasks.js +22 -0
- package/dist/api/tasks.js.map +1 -0
- package/dist/api/terminal.d.ts +7 -0
- package/dist/api/terminal.d.ts.map +1 -0
- package/dist/api/terminal.js +16 -0
- package/dist/api/terminal.js.map +1 -0
- package/dist/api/worktrees.d.ts +7 -0
- package/dist/api/worktrees.d.ts.map +1 -0
- package/dist/api/worktrees.js +26 -0
- package/dist/api/worktrees.js.map +1 -0
- package/dist/cli/arg-parser.d.ts +3 -0
- package/dist/cli/arg-parser.d.ts.map +1 -0
- package/dist/cli/arg-parser.js +243 -0
- package/dist/cli/arg-parser.js.map +1 -0
- package/dist/cli/config-resolver.d.ts +29 -0
- package/dist/cli/config-resolver.d.ts.map +1 -0
- package/dist/cli/config-resolver.js +139 -0
- package/dist/cli/config-resolver.js.map +1 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +224 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/constants.d.ts +7 -0
- package/dist/cli/constants.d.ts.map +1 -0
- package/dist/cli/constants.js +15 -0
- package/dist/cli/constants.js.map +1 -0
- package/dist/cli/help.d.ts +3 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +35 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/index.d.ts +23 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +23 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/plans-command.d.ts +3 -0
- package/dist/cli/plans-command.d.ts.map +1 -0
- package/dist/cli/plans-command.js +151 -0
- package/dist/cli/plans-command.js.map +1 -0
- package/dist/cli/server-starter.d.ts +26 -0
- package/dist/cli/server-starter.d.ts.map +1 -0
- package/dist/cli/server-starter.js +72 -0
- package/dist/cli/server-starter.js.map +1 -0
- package/dist/cli/types.d.ts +46 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/validation.d.ts +14 -0
- package/dist/cli/validation.d.ts.map +1 -0
- package/dist/cli/validation.js +99 -0
- package/dist/cli/validation.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +73 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/agent-commands.d.ts +27 -0
- package/dist/config/agent-commands.d.ts.map +1 -0
- package/dist/config/agent-commands.js +56 -0
- package/dist/config/agent-commands.js.map +1 -0
- package/dist/config/constants.d.ts +35 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +35 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/developer-messages.d.ts +2 -0
- package/dist/config/developer-messages.d.ts.map +1 -0
- package/dist/config/developer-messages.js +43 -0
- package/dist/config/developer-messages.js.map +1 -0
- package/dist/core/agents.d.ts +23 -0
- package/dist/core/agents.d.ts.map +1 -0
- package/dist/core/agents.js +91 -0
- package/dist/core/agents.js.map +1 -0
- package/dist/core/auth.d.ts +3 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +69 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/automation/branch.d.ts +18 -0
- package/dist/core/automation/branch.d.ts.map +1 -0
- package/dist/core/automation/branch.js +29 -0
- package/dist/core/automation/branch.js.map +1 -0
- package/dist/core/automation/git-orchestration.d.ts +51 -0
- package/dist/core/automation/git-orchestration.d.ts.map +1 -0
- package/dist/core/automation/git-orchestration.js +25 -0
- package/dist/core/automation/git-orchestration.js.map +1 -0
- package/dist/core/automation/plan.d.ts +15 -0
- package/dist/core/automation/plan.d.ts.map +1 -0
- package/dist/core/automation/plan.js +25 -0
- package/dist/core/automation/plan.js.map +1 -0
- package/dist/core/automation/request-validation.d.ts +45 -0
- package/dist/core/automation/request-validation.d.ts.map +1 -0
- package/dist/core/automation/request-validation.js +144 -0
- package/dist/core/automation/request-validation.js.map +1 -0
- package/dist/core/automation/task-runner.d.ts +42 -0
- package/dist/core/automation/task-runner.d.ts.map +1 -0
- package/dist/core/automation/task-runner.js +215 -0
- package/dist/core/automation/task-runner.js.map +1 -0
- package/dist/core/branch-name.d.ts +13 -0
- package/dist/core/branch-name.d.ts.map +1 -0
- package/dist/core/branch-name.js +429 -0
- package/dist/core/branch-name.js.map +1 -0
- package/dist/core/default-branch.d.ts +12 -0
- package/dist/core/default-branch.d.ts.map +1 -0
- package/dist/core/default-branch.js +78 -0
- package/dist/core/default-branch.js.map +1 -0
- package/dist/core/event-bus.d.ts +73 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +127 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/git.d.ts +13 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +15 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/github.d.ts +10 -0
- package/dist/core/github.d.ts.map +1 -0
- package/dist/core/github.js +245 -0
- package/dist/core/github.js.map +1 -0
- package/dist/core/plan-storage.d.ts +46 -0
- package/dist/core/plan-storage.d.ts.map +1 -0
- package/dist/core/plan-storage.js +237 -0
- package/dist/core/plan-storage.js.map +1 -0
- package/dist/core/plan.d.ts +23 -0
- package/dist/core/plan.d.ts.map +1 -0
- package/dist/core/plan.js +445 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/core/repositories.d.ts +2 -0
- package/dist/core/repositories.d.ts.map +1 -0
- package/dist/core/repositories.js +58 -0
- package/dist/core/repositories.js.map +1 -0
- package/dist/core/repository-config.d.ts +9 -0
- package/dist/core/repository-config.d.ts.map +1 -0
- package/dist/core/repository-config.js +65 -0
- package/dist/core/repository-config.js.map +1 -0
- package/dist/core/task-store.d.ts +14 -0
- package/dist/core/task-store.d.ts.map +1 -0
- package/dist/core/task-store.js +105 -0
- package/dist/core/task-store.js.map +1 -0
- package/dist/core/tasks.d.ts +62 -0
- package/dist/core/tasks.d.ts.map +1 -0
- package/dist/core/tasks.js +582 -0
- package/dist/core/tasks.js.map +1 -0
- package/dist/core/terminal-sessions.d.ts +18 -0
- package/dist/core/terminal-sessions.d.ts.map +1 -0
- package/dist/core/terminal-sessions.js +539 -0
- package/dist/core/terminal-sessions.js.map +1 -0
- package/dist/core/tmux.d.ts +29 -0
- package/dist/core/tmux.d.ts.map +1 -0
- package/dist/core/tmux.js +151 -0
- package/dist/core/tmux.js.map +1 -0
- package/dist/core/workdir.d.ts +8 -0
- package/dist/core/workdir.d.ts.map +1 -0
- package/dist/core/workdir.js +26 -0
- package/dist/core/workdir.js.map +1 -0
- package/dist/domain/branch-validator.d.ts +51 -0
- package/dist/domain/branch-validator.d.ts.map +1 -0
- package/dist/domain/branch-validator.js +88 -0
- package/dist/domain/branch-validator.js.map +1 -0
- package/dist/domain/git-url-parser.d.ts +27 -0
- package/dist/domain/git-url-parser.d.ts.map +1 -0
- package/dist/domain/git-url-parser.js +84 -0
- package/dist/domain/git-url-parser.js.map +1 -0
- package/dist/domain/index.d.ts +8 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +5 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/repository.d.ts +55 -0
- package/dist/domain/repository.d.ts.map +1 -0
- package/dist/domain/repository.js +73 -0
- package/dist/domain/repository.js.map +1 -0
- package/dist/domain/worktree.d.ts +43 -0
- package/dist/domain/worktree.d.ts.map +1 -0
- package/dist/domain/worktree.js +57 -0
- package/dist/domain/worktree.js.map +1 -0
- package/dist/infrastructure/cookies/cookie-manager.d.ts +18 -0
- package/dist/infrastructure/cookies/cookie-manager.d.ts.map +1 -0
- package/dist/infrastructure/cookies/cookie-manager.js +20 -0
- package/dist/infrastructure/cookies/cookie-manager.js.map +1 -0
- package/dist/infrastructure/cookies/cookie-parser.d.ts +43 -0
- package/dist/infrastructure/cookies/cookie-parser.d.ts.map +1 -0
- package/dist/infrastructure/cookies/cookie-parser.js +88 -0
- package/dist/infrastructure/cookies/cookie-parser.js.map +1 -0
- package/dist/infrastructure/cookies/cookie-security.d.ts +15 -0
- package/dist/infrastructure/cookies/cookie-security.d.ts.map +1 -0
- package/dist/infrastructure/cookies/cookie-security.js +35 -0
- package/dist/infrastructure/cookies/cookie-security.js.map +1 -0
- package/dist/infrastructure/cookies/index.d.ts +7 -0
- package/dist/infrastructure/cookies/index.d.ts.map +1 -0
- package/dist/infrastructure/cookies/index.js +4 -0
- package/dist/infrastructure/cookies/index.js.map +1 -0
- package/dist/infrastructure/errors/error-handler.d.ts +22 -0
- package/dist/infrastructure/errors/error-handler.d.ts.map +1 -0
- package/dist/infrastructure/errors/error-handler.js +89 -0
- package/dist/infrastructure/errors/error-handler.js.map +1 -0
- package/dist/infrastructure/errors/http-error.d.ts +30 -0
- package/dist/infrastructure/errors/http-error.d.ts.map +1 -0
- package/dist/infrastructure/errors/http-error.js +46 -0
- package/dist/infrastructure/errors/http-error.js.map +1 -0
- package/dist/infrastructure/errors/index.d.ts +5 -0
- package/dist/infrastructure/errors/index.d.ts.map +1 -0
- package/dist/infrastructure/errors/index.js +5 -0
- package/dist/infrastructure/errors/index.js.map +1 -0
- package/dist/infrastructure/errors/not-found-error.d.ts +8 -0
- package/dist/infrastructure/errors/not-found-error.d.ts.map +1 -0
- package/dist/infrastructure/errors/not-found-error.js +13 -0
- package/dist/infrastructure/errors/not-found-error.js.map +1 -0
- package/dist/infrastructure/errors/validation-error.d.ts +21 -0
- package/dist/infrastructure/errors/validation-error.d.ts.map +1 -0
- package/dist/infrastructure/errors/validation-error.js +31 -0
- package/dist/infrastructure/errors/validation-error.js.map +1 -0
- package/dist/infrastructure/logging/index.d.ts +3 -0
- package/dist/infrastructure/logging/index.d.ts.map +1 -0
- package/dist/infrastructure/logging/index.js +2 -0
- package/dist/infrastructure/logging/index.js.map +1 -0
- package/dist/infrastructure/logging/logger.d.ts +21 -0
- package/dist/infrastructure/logging/logger.d.ts.map +1 -0
- package/dist/infrastructure/logging/logger.js +49 -0
- package/dist/infrastructure/logging/logger.js.map +1 -0
- package/dist/repositories/git-repository.d.ts +67 -0
- package/dist/repositories/git-repository.d.ts.map +1 -0
- package/dist/repositories/git-repository.js +111 -0
- package/dist/repositories/git-repository.js.map +1 -0
- package/dist/repositories/git-status-repository.d.ts +22 -0
- package/dist/repositories/git-status-repository.d.ts.map +1 -0
- package/dist/repositories/git-status-repository.js +620 -0
- package/dist/repositories/git-status-repository.js.map +1 -0
- package/dist/repositories/repository-repository.d.ts +44 -0
- package/dist/repositories/repository-repository.d.ts.map +1 -0
- package/dist/repositories/repository-repository.js +155 -0
- package/dist/repositories/repository-repository.js.map +1 -0
- package/dist/repositories/worktree-repository.d.ts +66 -0
- package/dist/repositories/worktree-repository.d.ts.map +1 -0
- package/dist/repositories/worktree-repository.js +330 -0
- package/dist/repositories/worktree-repository.js.map +1 -0
- package/dist/server/cookies.d.ts +6 -0
- package/dist/server/cookies.d.ts.map +1 -0
- package/dist/server/cookies.js +6 -0
- package/dist/server/cookies.js.map +1 -0
- package/dist/server/events.d.ts +8 -0
- package/dist/server/events.d.ts.map +1 -0
- package/dist/server/events.js +128 -0
- package/dist/server/events.js.map +1 -0
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +173 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/router.d.ts +16 -0
- package/dist/server/router.d.ts.map +1 -0
- package/dist/server/router.js +256 -0
- package/dist/server/router.js.map +1 -0
- package/dist/server/ui.d.ts +8 -0
- package/dist/server/ui.d.ts.map +1 -0
- package/dist/server/ui.js +211 -0
- package/dist/server/ui.js.map +1 -0
- package/dist/server/websocket.d.ts +9 -0
- package/dist/server/websocket.d.ts.map +1 -0
- package/dist/server/websocket.js +116 -0
- package/dist/server/websocket.js.map +1 -0
- package/dist/services/auth-service.d.ts +49 -0
- package/dist/services/auth-service.d.ts.map +1 -0
- package/dist/services/auth-service.js +53 -0
- package/dist/services/auth-service.js.map +1 -0
- package/dist/services/index.d.ts +11 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/repository-service.d.ts +57 -0
- package/dist/services/repository-service.d.ts.map +1 -0
- package/dist/services/repository-service.js +62 -0
- package/dist/services/repository-service.js.map +1 -0
- package/dist/services/session-service.d.ts +31 -0
- package/dist/services/session-service.d.ts.map +1 -0
- package/dist/services/session-service.js +134 -0
- package/dist/services/session-service.js.map +1 -0
- package/dist/services/terminal-service.d.ts +43 -0
- package/dist/services/terminal-service.d.ts.map +1 -0
- package/dist/services/terminal-service.js +85 -0
- package/dist/services/terminal-service.js.map +1 -0
- package/dist/services/worktree-service.d.ts +39 -0
- package/dist/services/worktree-service.d.ts.map +1 -0
- package/dist/services/worktree-service.js +208 -0
- package/dist/services/worktree-service.js.map +1 -0
- package/dist/types/auth.d.ts +35 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/config.d.ts +46 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/git.d.ts +190 -0
- package/dist/types/git.d.ts.map +1 -0
- package/dist/types/git.js +5 -0
- package/dist/types/git.js.map +1 -0
- package/dist/types/http.d.ts +46 -0
- package/dist/types/http.d.ts.map +1 -0
- package/dist/types/http.js +2 -0
- package/dist/types/http.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/plan.d.ts +31 -0
- package/dist/types/plan.d.ts.map +1 -0
- package/dist/types/plan.js +5 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/services.d.ts +99 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +2 -0
- package/dist/types/services.js.map +1 -0
- package/dist/types/tasks.d.ts +68 -0
- package/dist/types/tasks.d.ts.map +1 -0
- package/dist/types/tasks.js +5 -0
- package/dist/types/tasks.js.map +1 -0
- package/dist/types/terminal.d.ts +60 -0
- package/dist/types/terminal.d.ts.map +1 -0
- package/dist/types/terminal.js +2 -0
- package/dist/types/terminal.js.map +1 -0
- package/dist/utils/cookies.d.ts +7 -0
- package/dist/utils/cookies.d.ts.map +1 -0
- package/dist/utils/cookies.js +6 -0
- package/dist/utils/cookies.js.map +1 -0
- package/dist/utils/http.d.ts +23 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +58 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/random.d.ts +12 -0
- package/dist/utils/random.d.ts.map +1 -0
- package/dist/utils/random.js +25 -0
- package/dist/utils/random.js.map +1 -0
- package/dist/utils/repository-cache.d.ts +8 -0
- package/dist/utils/repository-cache.d.ts.map +1 -0
- package/dist/utils/repository-cache.js +13 -0
- package/dist/utils/repository-cache.js.map +1 -0
- package/dist/validation/index.d.ts +9 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +6 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/request-validator.d.ts +99 -0
- package/dist/validation/request-validator.d.ts.map +1 -0
- package/dist/validation/request-validator.js +189 -0
- package/dist/validation/request-validator.js.map +1 -0
- package/dist/validation/schemas/repository-schema.d.ts +26 -0
- package/dist/validation/schemas/repository-schema.d.ts.map +1 -0
- package/dist/validation/schemas/repository-schema.js +31 -0
- package/dist/validation/schemas/repository-schema.js.map +1 -0
- package/dist/validation/schemas/terminal-schema.d.ts +21 -0
- package/dist/validation/schemas/terminal-schema.d.ts.map +1 -0
- package/dist/validation/schemas/terminal-schema.js +38 -0
- package/dist/validation/schemas/terminal-schema.js.map +1 -0
- package/dist/validation/schemas/worktree-schema.d.ts +21 -0
- package/dist/validation/schemas/worktree-schema.d.ts.map +1 -0
- package/dist/validation/schemas/worktree-schema.js +29 -0
- package/dist/validation/schemas/worktree-schema.js.map +1 -0
- package/package.json +79 -0
- package/ui/dist/assets/index-BDDrbP3l.js +354 -0
- package/ui/dist/assets/index-CwB7gOl4.css +41 -0
- package/ui/dist/index.html +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# agentrix
|
|
2
|
+
|
|
3
|
+
`agentrix` is a password-protected CLI that serves a browser-based interface for managing
|
|
4
|
+
Git repositories, worktrees, and persistent shell sessions. The backend is an ES module Node.js
|
|
5
|
+
service that exposes REST + WebSocket APIs, while the frontend is a Vite-powered React application
|
|
6
|
+
that lives in `ui/`.
|
|
7
|
+
|
|
8
|
+
## Prerequisites
|
|
9
|
+
|
|
10
|
+
- Node.js 18 or newer
|
|
11
|
+
- Git (for cloning repositories and creating worktrees)
|
|
12
|
+
|
|
13
|
+
## Install Dependencies
|
|
14
|
+
|
|
15
|
+
From the repository root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Install frontend dependencies separately:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd ui
|
|
25
|
+
npm install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Build the Frontend
|
|
29
|
+
|
|
30
|
+
The backend serves pre-built assets from `ui/dist`. Build them once (or whenever the UI changes):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run build # Invokes `vite build` in ui/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The build artefacts land in `ui/dist/` and are picked up automatically by the CLI defaults.
|
|
37
|
+
|
|
38
|
+
## Running the CLI
|
|
39
|
+
|
|
40
|
+
After building the UI:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm start
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
or directly:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node bin/agentrix.js
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
By default the server binds to `0.0.0.0:3414`, serves assets from `ui/dist`, and scans the current
|
|
53
|
+
working directory for repositories. Customise behaviour with flags:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
node bin/agentrix.js \
|
|
57
|
+
--port 4000 \
|
|
58
|
+
--host 127.0.0.1 \
|
|
59
|
+
--ui ./ui/dist \
|
|
60
|
+
--workdir /path/to/workdir \
|
|
61
|
+
--password secret
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### CLI Options
|
|
65
|
+
|
|
66
|
+
- `-p, --port <number>` – HTTP port (default: `3414`)
|
|
67
|
+
- `-H, --host <host>` – Bind address (default: `0.0.0.0`)
|
|
68
|
+
- `-u, --ui <path>` – Directory or entry file for the built UI (default: `ui/dist`)
|
|
69
|
+
- `-w, --workdir <path>` – Root directory that holds `org/repo` folders (default: process CWD)
|
|
70
|
+
- `-P, --password <string>` – UI password (default: secure random string generated at startup)
|
|
71
|
+
- `--default-branch <name>` – Override the sync branch when repositories use a non-`main` default
|
|
72
|
+
- `--terminal-session-mode <auto|tmux|pty>` – Select the terminal backend (`auto` tries tmux, falls back to PTY)
|
|
73
|
+
- `--force-tmux` – Shortcut for `--terminal-session-mode tmux`; errors if tmux is unavailable
|
|
74
|
+
- `--no-tmux` – Shortcut for `--terminal-session-mode pty`; disables tmux usage entirely
|
|
75
|
+
- `--show-password` – Print the resolved password even if it was set via config or flag
|
|
76
|
+
- `--ngrok-api-key <token>` – Authtoken used to establish a public ngrok tunnel
|
|
77
|
+
- `--ngrok-domain <domain>` – Reserved ngrok domain exposed when tunnelling (requires `--ngrok-api-key`)
|
|
78
|
+
- `--save` – Persist the effective configuration to `~/.agentrix/config.json` and exit
|
|
79
|
+
- `-h, --help` – Print usage
|
|
80
|
+
- `-v, --version` – Show package version
|
|
81
|
+
|
|
82
|
+
When both ngrok flags are supplied the CLI will establish a tunnel after the HTTP server boots and
|
|
83
|
+
print the public URL. If either flag is omitted the service remains reachable only via the bound host
|
|
84
|
+
and port.
|
|
85
|
+
|
|
86
|
+
### Configuration File
|
|
87
|
+
|
|
88
|
+
At startup the CLI also reads `~/.agentrix/config.json` if it exists. Any values in that file
|
|
89
|
+
fill in defaults for matching CLI options, while explicit command-line arguments always win. A simple
|
|
90
|
+
configuration might look like:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"port": 4001,
|
|
95
|
+
"host": "127.0.0.1",
|
|
96
|
+
"ui": "./ui/dist",
|
|
97
|
+
"workdir": "/srv/worktrees",
|
|
98
|
+
"password": "s3cr3t",
|
|
99
|
+
"defaultBranch": "develop",
|
|
100
|
+
"defaultBranches": {
|
|
101
|
+
"acme/web": "master"
|
|
102
|
+
},
|
|
103
|
+
"cookies": {
|
|
104
|
+
"secure": "auto"
|
|
105
|
+
},
|
|
106
|
+
"commands": {
|
|
107
|
+
"codex": "codex",
|
|
108
|
+
"cursor": "cursor-agent",
|
|
109
|
+
"vscode": "code ."
|
|
110
|
+
},
|
|
111
|
+
"ngrok": {
|
|
112
|
+
"apiKey": "NGROK_AUTHTOKEN",
|
|
113
|
+
"domain": "example.ngrok.app"
|
|
114
|
+
},
|
|
115
|
+
"automation": {
|
|
116
|
+
"apiKey": "AUTOMATION_API_KEY"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Supported keys mirror the CLI flags (`port`, `host`, `ui`, `workdir`, `password`, individual
|
|
122
|
+
`*Command` entries, plus `ngrokApiKey`/`ngrokDomain` or `ngrok.apiKey` / `ngrok.domain`). The
|
|
123
|
+
automation API key can be supplied as `automation.apiKey`, `automationApiKey`, or `apiKey`. Leave
|
|
124
|
+
the file absent to continue using only CLI arguments. Use `terminalSessionMode` to persist the
|
|
125
|
+
preferred terminal backend (`auto`, `tmux`, or `pty`).
|
|
126
|
+
|
|
127
|
+
Run `agentrix --port 4001 --workdir /srv/worktrees --save` to save the provided values into
|
|
128
|
+
the config file without starting the server.
|
|
129
|
+
|
|
130
|
+
### Authentication
|
|
131
|
+
|
|
132
|
+
When the CLI generates a password it prints the value once at startup. If you supply a password via
|
|
133
|
+
CLI flag or config file it is kept out of stdout; pass `--show-password` if you still need the value
|
|
134
|
+
echoed. Clients must authenticate before calling API endpoints.
|
|
135
|
+
|
|
136
|
+
Repositories that do not use `main` can set a global `defaultBranch` or repo-specific overrides in
|
|
137
|
+
`defaultBranches` (keyed by `org/repo`). The CLI uses these when syncing before creating worktrees.
|
|
138
|
+
Successful logins receive an HTTP-only session cookie; log out via the UI or `POST
|
|
139
|
+
/api/auth/logout`. On shutdown the backend cleans up shell sessions, tmux attachments, and WebSocket
|
|
140
|
+
clients.
|
|
141
|
+
|
|
142
|
+
### Automation API
|
|
143
|
+
|
|
144
|
+
When `config.json` includes an automation API key the backend exposes a machine-consumable endpoint
|
|
145
|
+
for provisioning worktrees and launching agents.
|
|
146
|
+
|
|
147
|
+
- Endpoint: `POST /api/automation/launch`
|
|
148
|
+
- Headers: `X-API-Key: <key>` (alternatively `Authorization: Bearer <key>`)
|
|
149
|
+
- Body shape:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"repo": "org/repository",
|
|
154
|
+
"worktree": "type/title",
|
|
155
|
+
"command": "codex",
|
|
156
|
+
"prompt": "Kick off the task at hand",
|
|
157
|
+
"plan": true
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The server uses `codex`, `cursor`, or `claude` agent commands configured via `config.json`, cloning
|
|
162
|
+
`git@github.com:org/repository.git` if necessary, creating (or reusing) the specified worktree, and
|
|
163
|
+
then launching the agent inside the same tmux-backed terminal session that the UI attaches to. When
|
|
164
|
+
`plan` is omitted or set to `true` the submitted prompt is first transformed via the **Create Plan**
|
|
165
|
+
pipeline (powered by the configured local LLM); set `"plan": false` to preserve the original prompt and bypass
|
|
166
|
+
planning. The request responds with `202 Accepted` once the terminal session is ready and includes
|
|
167
|
+
metadata about the repository, worktree, agent command, process `pid`, terminal identifiers
|
|
168
|
+
(`terminalSessionId`, `terminalSessionCreated`, `terminalUsingTmux`, `tmuxSessionName` when
|
|
169
|
+
applicable), plus the automation metadata `plan`, `promptRoute`, and `automationRequestId`. Automated
|
|
170
|
+
launches therefore appear immediately inside the UI terminal. The effective prompt (planned or
|
|
171
|
+
passthrough) is exported to the session as `AGENTRIX_PROMPT` and appended to the initial
|
|
172
|
+
agent command so automation invocations receive it straight away.
|
|
173
|
+
|
|
174
|
+
### Task Persistence
|
|
175
|
+
|
|
176
|
+
Automation launches and other background workflows publish task status updates that power
|
|
177
|
+
`/api/tasks` and the UI dashboard. The backend persists this metadata to
|
|
178
|
+
`<workdir>/.agentrix/tasks.json` using atomic writes so that state survives process
|
|
179
|
+
restarts. During bootstrap the saved snapshot is rehydrated; any task that was still `pending` or
|
|
180
|
+
`running` is marked as `failed` with `error.reason` set to `process_restart`, allowing the UI to show
|
|
181
|
+
that progress was interrupted. Completed tasks remain visible for 15 minutes before being pruned
|
|
182
|
+
from both memory and disk.
|
|
183
|
+
|
|
184
|
+
### Plan Artifacts
|
|
185
|
+
|
|
186
|
+
Automation runs (and prompt-driven worktree creation) persist Markdown plans inside each worktree
|
|
187
|
+
under `.plans/`. Access them without SSHing into the worktree:
|
|
188
|
+
|
|
189
|
+
- `GET /api/plans?org=<org>&repo=<repo>&branch=<branch>` – returns the newest plan identifiers and
|
|
190
|
+
timestamps for the requested worktree.
|
|
191
|
+
- `GET /api/plans/content?...&planId=<file>` – streams the selected plan’s contents in Markdown.
|
|
192
|
+
- CLI helper: `agentrix plans list --org <org> --repo <repo> --branch <branch>` followed by
|
|
193
|
+
`agentrix plans show --org <org> --repo <repo> --branch <branch> --plan-id <file>` to
|
|
194
|
+
render Markdown locally.
|
|
195
|
+
|
|
196
|
+
The server prunes older artifacts, keeping the 20 most recent plans per branch by default. Delete
|
|
197
|
+
entries manually if you need to reclaim space sooner.
|
|
198
|
+
|
|
199
|
+
### Real-time Updates
|
|
200
|
+
|
|
201
|
+
After authentication the UI opens a Server-Sent Events stream at `GET /api/events` to receive
|
|
202
|
+
push notifications:
|
|
203
|
+
|
|
204
|
+
- `repos:update` — emits the full repository/worktree snapshot (equivalent to `GET /api/repos`).
|
|
205
|
+
- `sessions:update` — lists active terminal sessions (subset of `GET /api/sessions`).
|
|
206
|
+
|
|
207
|
+
When the stream is unavailable the client automatically falls back to minute-level polling to keep
|
|
208
|
+
state in sync.
|
|
209
|
+
|
|
210
|
+
### Repository Layout & Worktrees
|
|
211
|
+
|
|
212
|
+
The work directory is expected to follow:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
[workdir]/
|
|
216
|
+
org/
|
|
217
|
+
repo/
|
|
218
|
+
repository/ # main checkout
|
|
219
|
+
<worktree-name>/ # additional worktrees
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Use **Add Repo** to clone into this structure, **Create Worktree** to branch from up-to-date
|
|
223
|
+
`origin/main`, and **Delete Worktree** to remove worktrees (except `main`, which is intentionally
|
|
224
|
+
protected). Terminal sessions are backed by `node-pty` and optionally tmux so reconnects resume the
|
|
225
|
+
previous shell.
|
|
226
|
+
|
|
227
|
+
## Development Workflow
|
|
228
|
+
|
|
229
|
+
- `npm run dev` – Start the backend CLI.
|
|
230
|
+
- `npm run dev:ui` – Run the Vite dev server (hot-module reloading React).
|
|
231
|
+
- `npm run preview` – Serve the production build through Vite.
|
|
232
|
+
- `npm run build` – Generate production assets in `ui/dist`.
|
|
233
|
+
|
|
234
|
+
During local development run the backend CLI (`npm run dev`) alongside the Vite dev server (`npm run
|
|
235
|
+
dev:ui`). Use the dev server URL directly in the browser while exercising APIs exposed by the CLI.
|
package/bin/agentrix.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RequestContext } from '../types/http.js';
|
|
2
|
+
import type { AuthManager, CookieManager } from '../types/auth.js';
|
|
3
|
+
export declare function createAuthHandlers(authManager: AuthManager, { cookieManager }?: {
|
|
4
|
+
cookieManager?: CookieManager;
|
|
5
|
+
}): {
|
|
6
|
+
login: (context: RequestContext) => Promise<void>;
|
|
7
|
+
logout: (context: RequestContext) => Promise<void>;
|
|
8
|
+
status: (context: RequestContext) => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEnE,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,EAAE,aAAa,EAAE,GAAE;IAAE,aAAa,CAAC,EAAE,aAAa,CAAA;CAAO;;;;EAiC1D"}
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { sendJson } from '../utils/http.js';
|
|
2
|
+
import { createAuthService } from '../services/index.js';
|
|
3
|
+
import { asyncHandler } from '../infrastructure/errors/index.js';
|
|
4
|
+
import { createSimpleHandler } from './base-handler.js';
|
|
5
|
+
export function createAuthHandlers(authManager, { cookieManager } = {}) {
|
|
6
|
+
const authService = createAuthService(authManager, cookieManager);
|
|
7
|
+
// Login requires special error handling for status codes
|
|
8
|
+
const login = asyncHandler(async (context) => {
|
|
9
|
+
const payload = await context.readJsonBody();
|
|
10
|
+
const password = typeof payload['password'] === 'string' ? payload['password'].trim() : '';
|
|
11
|
+
try {
|
|
12
|
+
const result = await authService.login(context.req, context.res, password);
|
|
13
|
+
sendJson(context.res, 200, result);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
// Auth errors need special handling for status codes
|
|
17
|
+
const err = error;
|
|
18
|
+
const statusCode = err.statusCode || (err.message === 'Invalid password' ? 401 : 400);
|
|
19
|
+
sendJson(context.res, statusCode, { error: err.message });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const logout = createSimpleHandler(async (context) => authService.logout(context.req, context.res));
|
|
23
|
+
const status = createSimpleHandler(async (context) => authService.getStatus(context.req));
|
|
24
|
+
return {
|
|
25
|
+
login,
|
|
26
|
+
logout,
|
|
27
|
+
status,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAIxD,MAAM,UAAU,kBAAkB,CAChC,WAAwB,EACxB,EAAE,aAAa,KAAwC,EAAE;IAEzD,MAAM,WAAW,GAAG,iBAAiB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAElE,yDAAyD;IACzD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,OAAuB,EAAE,EAAE;QAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,OAAO,OAAO,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAE3F,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC3E,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,qDAAqD;YACrD,MAAM,GAAG,GAAG,KAAiD,CAAC;YAC9D,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,OAAO,KAAK,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACtF,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,mBAAmB,CAChC,KAAK,EAAE,OAAuB,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAChF,CAAC;IAEF,MAAM,MAAM,GAAG,mBAAmB,CAChC,KAAK,EAAE,OAAuB,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CACtE,CAAC;IAEF,OAAO;QACL,KAAK;QACL,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { launchAgentProcess } from '../core/agents.js';
|
|
2
|
+
import { runTask } from '../core/tasks.js';
|
|
3
|
+
import type { Logger } from '../infrastructure/logging/index.js';
|
|
4
|
+
declare function ensureRepositoryExists(workdir: string, org: string, repo: string): Promise<{
|
|
5
|
+
repositoryPath: string;
|
|
6
|
+
cloned: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
declare function ensureWorktreeExists(workdir: string, org: string, repo: string, branch: string, options?: unknown): Promise<{
|
|
9
|
+
worktreePath: string;
|
|
10
|
+
created: boolean;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const automationPlanMetrics: {
|
|
13
|
+
planTrue: {
|
|
14
|
+
requests: number;
|
|
15
|
+
successes: number;
|
|
16
|
+
failures: number;
|
|
17
|
+
totalLatencyMs: number;
|
|
18
|
+
};
|
|
19
|
+
planFalse: {
|
|
20
|
+
requests: number;
|
|
21
|
+
successes: number;
|
|
22
|
+
failures: number;
|
|
23
|
+
totalLatencyMs: number;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export declare function resetAutomationPlanMetrics(): void;
|
|
27
|
+
export interface AutomationHandlersConfig {
|
|
28
|
+
workdir: string;
|
|
29
|
+
agentCommands: unknown;
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
branchNameGenerator: unknown;
|
|
32
|
+
planService: unknown;
|
|
33
|
+
logger?: Logger;
|
|
34
|
+
defaultBranches: unknown;
|
|
35
|
+
}
|
|
36
|
+
export interface AutomationHandlersDependencies {
|
|
37
|
+
ensureRepositoryExists?: typeof ensureRepositoryExists;
|
|
38
|
+
ensureWorktreeExists?: typeof ensureWorktreeExists;
|
|
39
|
+
launchAgentProcess?: typeof launchAgentProcess;
|
|
40
|
+
runTaskImpl?: typeof runTask;
|
|
41
|
+
now?: () => number;
|
|
42
|
+
createRequestId?: () => string;
|
|
43
|
+
}
|
|
44
|
+
export declare function createAutomationHandlers({ workdir, agentCommands, apiKey, branchNameGenerator, planService, logger, defaultBranches, }: AutomationHandlersConfig, { ensureRepositoryExists: ensureRepoExists, ensureWorktreeExists: ensureWorktree, launchAgentProcess: launchAgent, runTaskImpl, now, createRequestId, }?: AutomationHandlersDependencies): {
|
|
45
|
+
launch: (context: {
|
|
46
|
+
req: unknown;
|
|
47
|
+
res: unknown;
|
|
48
|
+
readJsonBody: () => Promise<unknown>;
|
|
49
|
+
}) => Promise<void>;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=automation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automation.d.ts","sourceRoot":"","sources":["../../src/api/automation.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAW3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAEjE,iBAAe,sBAAsB,CACnC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CActD;AAED,iBAAe,oBAAoB,CACjC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,OAAY,GACpB,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAarD;AAED,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAajC,CAAC;AAEF,wBAAgB,0BAA0B,SAOzC;AAeD,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,8BAA8B;IAC7C,sBAAsB,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACvD,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACnD,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,WAAW,CAAC,EAAE,OAAO,OAAO,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;CAChC;AAED,wBAAgB,wBAAwB,CACtC,EACE,OAAO,EACP,aAAa,EACb,MAAM,EACN,mBAAmB,EACnB,WAAW,EACX,MAAM,EACN,eAAe,GAChB,EAAE,wBAAwB,EAC3B,EACE,sBAAsB,EAAE,gBAAyC,EACjE,oBAAoB,EAAE,cAAqC,EAC3D,kBAAkB,EAAE,WAAgC,EACpD,WAAqB,EACrB,GAAsB,EACtB,eAAoC,GACrC,GAAE,8BAAmC;sBASP;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,KAAG,OAAO,CAAC,IAAI,CAAC;EAoHpH"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { cloneRepository, createWorktree, ensureRepository, getWorktreePath, } from '../core/git.js';
|
|
3
|
+
import { launchAgentProcess } from '../core/agents.js';
|
|
4
|
+
import { runTask } from '../core/tasks.js';
|
|
5
|
+
import { sendJson } from '../utils/http.js';
|
|
6
|
+
import { validateAutomationRequest, AutomationRequestError, } from '../core/automation/request-validation.js';
|
|
7
|
+
import { resolveBranchName } from '../core/automation/branch.js';
|
|
8
|
+
import { generatePlanText } from '../core/automation/plan.js';
|
|
9
|
+
import { createGitOrchestrator } from '../core/automation/git-orchestration.js';
|
|
10
|
+
import { runAutomationTask } from '../core/automation/task-runner.js';
|
|
11
|
+
import { createLogger } from '../infrastructure/logging/index.js';
|
|
12
|
+
async function ensureRepositoryExists(workdir, org, repo) {
|
|
13
|
+
try {
|
|
14
|
+
const { repositoryPath } = await ensureRepository(workdir, org, repo);
|
|
15
|
+
return { repositoryPath, cloned: false };
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
const err = error;
|
|
19
|
+
if (err && /Repository not found/i.test(err.message || '')) {
|
|
20
|
+
const remote = `git@github.com:${org}/${repo}.git`;
|
|
21
|
+
await cloneRepository(workdir, remote);
|
|
22
|
+
const { repositoryPath } = await ensureRepository(workdir, org, repo);
|
|
23
|
+
return { repositoryPath, cloned: true };
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function ensureWorktreeExists(workdir, org, repo, branch, options = {}) {
|
|
29
|
+
try {
|
|
30
|
+
const { worktreePath } = await getWorktreePath(workdir, org, repo, branch);
|
|
31
|
+
return { worktreePath, created: false };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const err = error;
|
|
35
|
+
if (err && /worktree .* not found/i.test(err.message || '')) {
|
|
36
|
+
await createWorktree(workdir, org, repo, branch, options);
|
|
37
|
+
const { worktreePath } = await getWorktreePath(workdir, org, repo, branch);
|
|
38
|
+
return { worktreePath, created: true };
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export const automationPlanMetrics = {
|
|
44
|
+
planTrue: {
|
|
45
|
+
requests: 0,
|
|
46
|
+
successes: 0,
|
|
47
|
+
failures: 0,
|
|
48
|
+
totalLatencyMs: 0,
|
|
49
|
+
},
|
|
50
|
+
planFalse: {
|
|
51
|
+
requests: 0,
|
|
52
|
+
successes: 0,
|
|
53
|
+
failures: 0,
|
|
54
|
+
totalLatencyMs: 0,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
export function resetAutomationPlanMetrics() {
|
|
58
|
+
for (const bucket of Object.values(automationPlanMetrics)) {
|
|
59
|
+
bucket.requests = 0;
|
|
60
|
+
bucket.successes = 0;
|
|
61
|
+
bucket.failures = 0;
|
|
62
|
+
bucket.totalLatencyMs = 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function finishMetrics(key, success, durationMs) {
|
|
66
|
+
const bucket = automationPlanMetrics[key];
|
|
67
|
+
if (!bucket) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (success) {
|
|
71
|
+
bucket.successes += 1;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
bucket.failures += 1;
|
|
75
|
+
}
|
|
76
|
+
bucket.totalLatencyMs += durationMs;
|
|
77
|
+
}
|
|
78
|
+
export function createAutomationHandlers({ workdir, agentCommands, apiKey, branchNameGenerator, planService, logger, defaultBranches, }, { ensureRepositoryExists: ensureRepoExists = ensureRepositoryExists, ensureWorktreeExists: ensureWorktree = ensureWorktreeExists, launchAgentProcess: launchAgent = launchAgentProcess, runTaskImpl = runTask, now = () => Date.now(), createRequestId = () => randomUUID(), } = {}) {
|
|
79
|
+
const gitOrchestrator = createGitOrchestrator({
|
|
80
|
+
ensureRepositoryExists: ensureRepoExists,
|
|
81
|
+
ensureWorktreeExists: ensureWorktree,
|
|
82
|
+
});
|
|
83
|
+
const log = createLogger(logger);
|
|
84
|
+
async function launch(context) {
|
|
85
|
+
const ctx = context;
|
|
86
|
+
let validation;
|
|
87
|
+
try {
|
|
88
|
+
validation = await validateAutomationRequest({
|
|
89
|
+
req: ctx.req,
|
|
90
|
+
expectedApiKey: apiKey || '',
|
|
91
|
+
readJsonBody: ctx.readJsonBody,
|
|
92
|
+
agentCommands,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error instanceof AutomationRequestError) {
|
|
97
|
+
sendJson(ctx.res, error.status, { error: error.message });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
log.error('[agentrix] Automation validation failed unexpectedly.', error);
|
|
101
|
+
sendJson(ctx.res, 500, { error: 'Unexpected error while validating automation request' });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const { planEnabled, prompt, org, repo, worktreeInput, agent, routeLabel } = validation;
|
|
105
|
+
const metricsKey = planEnabled ? 'planTrue' : 'planFalse';
|
|
106
|
+
automationPlanMetrics[metricsKey].requests += 1;
|
|
107
|
+
const requestId = createRequestId();
|
|
108
|
+
const startedAt = now();
|
|
109
|
+
const elapsedMs = () => {
|
|
110
|
+
const value = now() - startedAt;
|
|
111
|
+
return Number.isFinite(value) ? value : 0;
|
|
112
|
+
};
|
|
113
|
+
const finishSuccess = (detail) => {
|
|
114
|
+
const durationMs = elapsedMs();
|
|
115
|
+
finishMetrics(metricsKey, true, durationMs);
|
|
116
|
+
const suffix = detail ? `: ${detail}` : '';
|
|
117
|
+
log.info(`[agentrix] Automation request ${requestId} (${routeLabel}) completed in ${durationMs}ms${suffix}`);
|
|
118
|
+
};
|
|
119
|
+
const finishFailure = (message, error) => {
|
|
120
|
+
const durationMs = elapsedMs();
|
|
121
|
+
finishMetrics(metricsKey, false, durationMs);
|
|
122
|
+
if (error) {
|
|
123
|
+
log.error(`[agentrix] Automation request ${requestId} (${routeLabel}) failed after ${durationMs}ms: ${message}`, error);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
log.error(`[agentrix] Automation request ${requestId} (${routeLabel}) failed after ${durationMs}ms: ${message}`);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
log.info(`[agentrix] Automation request ${requestId} (${routeLabel}) received.`);
|
|
130
|
+
if (planEnabled && !prompt.trim()) {
|
|
131
|
+
const message = 'prompt is required when plan is true';
|
|
132
|
+
finishFailure(message);
|
|
133
|
+
sendJson(ctx.res, 400, { error: message });
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const service = planService;
|
|
137
|
+
if (planEnabled && (!service || !service.isConfigured)) {
|
|
138
|
+
const message = 'Plan generation is not configured. Configure a local LLM command (set planLlm in config.json).';
|
|
139
|
+
finishFailure(message);
|
|
140
|
+
sendJson(ctx.res, 503, { error: message });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const result = (await runAutomationTask({
|
|
145
|
+
runTaskImpl: runTaskImpl,
|
|
146
|
+
resolveBranchName: resolveBranchName,
|
|
147
|
+
generatePlanText: generatePlanText,
|
|
148
|
+
gitOrchestrator,
|
|
149
|
+
launchAgent: launchAgent,
|
|
150
|
+
workdir,
|
|
151
|
+
planEnabled,
|
|
152
|
+
routeLabel,
|
|
153
|
+
prompt,
|
|
154
|
+
org,
|
|
155
|
+
repo,
|
|
156
|
+
agent: agent,
|
|
157
|
+
requestId,
|
|
158
|
+
worktreeInput,
|
|
159
|
+
branchNameGenerator,
|
|
160
|
+
defaultBranches,
|
|
161
|
+
planService,
|
|
162
|
+
finishSuccess: finishSuccess,
|
|
163
|
+
finishFailure: finishFailure,
|
|
164
|
+
onBranchResolved: (branch) => {
|
|
165
|
+
log.info(`[agentrix] Automation request ${requestId} (${routeLabel}) targeting ${org}/${repo}#${branch}.`);
|
|
166
|
+
},
|
|
167
|
+
}));
|
|
168
|
+
sendJson(ctx.res, 202, { taskId: result.taskId, data: result.queuedData });
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
const status = error instanceof AutomationRequestError && typeof error.status === 'number'
|
|
172
|
+
? error.status
|
|
173
|
+
: 500;
|
|
174
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
175
|
+
finishFailure(message, error instanceof Error ? error : undefined);
|
|
176
|
+
sendJson(ctx.res, status, { error: message });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return { launch };
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=automation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automation.js","sourceRoot":"","sources":["../../src/api/automation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACL,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAGlE,KAAK,UAAU,sBAAsB,CACnC,OAAe,EACf,GAAW,EACX,IAAY;IAEZ,IAAI,CAAC;QACH,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACtE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAA6B,CAAC;QAC1C,IAAI,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3D,MAAM,MAAM,GAAG,kBAAkB,GAAG,IAAI,IAAI,MAAM,CAAC;YACnD,MAAM,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACvC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACtE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,OAAe,EACf,GAAW,EACX,IAAY,EACZ,MAAc,EACd,UAAmB,EAAE;IAErB,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3E,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAA6B,CAAC;QAC1C,IAAI,GAAG,IAAI,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAC5D,MAAM,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAgB,CAAC,CAAC;YACnE,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAC3E,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,QAAQ,EAAE;QACR,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;QACX,cAAc,EAAE,CAAC;KAClB;IACD,SAAS,EAAE;QACT,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;QACX,cAAc,EAAE,CAAC;KAClB;CACF,CAAC;AAEF,MAAM,UAAU,0BAA0B;IACxC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;QACpB,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;QACrB,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;QACpB,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,GAA6B,EAAE,OAAgB,EAAE,UAAkB;IACxF,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,CAAC,cAAc,IAAI,UAAU,CAAC;AACtC,CAAC;AAqBD,MAAM,UAAU,wBAAwB,CACtC,EACE,OAAO,EACP,aAAa,EACb,MAAM,EACN,mBAAmB,EACnB,WAAW,EACX,MAAM,EACN,eAAe,GACU,EAC3B,EACE,sBAAsB,EAAE,gBAAgB,GAAG,sBAAsB,EACjE,oBAAoB,EAAE,cAAc,GAAG,oBAAoB,EAC3D,kBAAkB,EAAE,WAAW,GAAG,kBAAkB,EACpD,WAAW,GAAG,OAAO,EACrB,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EACtB,eAAe,GAAG,GAAG,EAAE,CAAC,UAAU,EAAE,MACF,EAAE;IAEtC,MAAM,eAAe,GAAG,qBAAqB,CAAC;QAC5C,sBAAsB,EAAE,gBAAgB;QACxC,oBAAoB,EAAE,cAAc;KACrC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAEjC,KAAK,UAAU,MAAM,CAAC,OAA6E;QACjG,MAAM,GAAG,GAAG,OAAsO,CAAC;QACnP,IAAI,UAAU,CAAC;QACf,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,yBAAyB,CAAC;gBAC3C,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,cAAc,EAAE,MAAM,IAAI,EAAE;gBAC5B,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,aAAa;aACd,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,sBAAsB,EAAE,CAAC;gBAC5C,QAAQ,CAAC,GAAG,CAAC,GAAgC,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvF,OAAO;YACT,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,uDAAuD,EAAE,KAAK,CAAC,CAAC;YAC1E,QAAQ,CAAC,GAAG,CAAC,GAAgC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,sDAAsD,EAAE,CAAC,CAAC;YACvH,OAAO;QACT,CAAC;QAED,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,CAAC;QAExF,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;QAC1D,qBAAqB,CAAC,UAAU,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC;QAEhD,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC;QAExB,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,MAAM,KAAK,GAAG,GAAG,EAAE,GAAG,SAAS,CAAC;YAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,MAAM,aAAa,GAAG,CAAC,MAAe,EAAQ,EAAE;YAC9C,MAAM,UAAU,GAAG,SAAS,EAAE,CAAC;YAC/B,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,IAAI,CACN,iCAAiC,SAAS,KAAK,UAAU,kBAAkB,UAAU,KAAK,MAAM,EAAE,CACnG,CAAC;QACJ,CAAC,CAAC;QAEF,MAAM,aAAa,GAAG,CAAC,OAAe,EAAE,KAAe,EAAQ,EAAE;YAC/D,MAAM,UAAU,GAAG,SAAS,EAAE,CAAC;YAC/B,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;YAC7C,IAAI,KAAK,EAAE,CAAC;gBACV,GAAG,CAAC,KAAK,CACP,iCAAiC,SAAS,KAAK,UAAU,kBAAkB,UAAU,OAAO,OAAO,EAAE,EACrG,KAAK,CACN,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,KAAK,CACP,iCAAiC,SAAS,KAAK,UAAU,kBAAkB,UAAU,OAAO,OAAO,EAAE,CACtG,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,iCAAiC,SAAS,KAAK,UAAU,aAAa,CAAC,CAAC;QAEjF,IAAI,WAAW,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,sCAAsC,CAAC;YACvD,aAAa,CAAC,OAAO,CAAC,CAAC;YACvB,QAAQ,CAAC,GAAG,CAAC,GAAgC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,WAAyC,CAAC;QAC1D,IAAI,WAAW,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACvD,MAAM,OAAO,GACX,gGAAgG,CAAC;YACnG,aAAa,CAAC,OAAO,CAAC,CAAC;YACvB,QAAQ,CAAC,GAAG,CAAC,GAAgC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,CAAC,MAAM,iBAAiB,CAAC;gBACtC,WAAW,EAAE,WAAoB;gBACjC,iBAAiB,EAAE,iBAA0B;gBAC7C,gBAAgB,EAAE,gBAAyB;gBAC3C,eAAe;gBACf,WAAW,EAAE,WAAoB;gBACjC,OAAO;gBACP,WAAW;gBACX,UAAU;gBACV,MAAM;gBACN,GAAG;gBACH,IAAI;gBACJ,KAAK,EAAE,KAA0B;gBACjC,SAAS;gBACT,aAAa;gBACb,mBAAmB;gBACnB,eAAe;gBACf,WAAW;gBACX,aAAa,EAAE,aAAsB;gBACrC,aAAa,EAAE,aAAsB;gBACrC,gBAAgB,EAAE,CAAC,MAAc,EAAE,EAAE;oBACnC,GAAG,CAAC,IAAI,CACN,iCAAiC,SAAS,KAAK,UAAU,eAAe,GAAG,IAAI,IAAI,IAAI,MAAM,GAAG,CACjG,CAAC;gBACJ,CAAC;aACF,CAAC,CAAuD,CAAC;YAE1D,QAAQ,CAAC,GAAG,CAAC,GAAgC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1G,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,MAAM,GACV,KAAK,YAAY,sBAAsB,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;gBACzE,CAAC,CAAC,KAAK,CAAC,MAAM;gBACd,CAAC,CAAC,GAAG,CAAC;YACV,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,aAAa,CAAC,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACnE,QAAQ,CAAC,GAAG,CAAC,GAAgC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { RequestContext } from '../types/http.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generic handler function type
|
|
4
|
+
*/
|
|
5
|
+
export type HandlerFunction<TInput = unknown, TOutput = unknown> = (input: TInput, context: RequestContext) => Promise<TOutput>;
|
|
6
|
+
/**
|
|
7
|
+
* Validation function type
|
|
8
|
+
*/
|
|
9
|
+
export type ValidationFunction<TInput = unknown> = (payload: unknown) => TInput;
|
|
10
|
+
/**
|
|
11
|
+
* Options for creating a handler
|
|
12
|
+
*/
|
|
13
|
+
export interface HandlerOptions<TInput, TOutput> {
|
|
14
|
+
/**
|
|
15
|
+
* The service method to call
|
|
16
|
+
*/
|
|
17
|
+
handler: HandlerFunction<TInput, TOutput>;
|
|
18
|
+
/**
|
|
19
|
+
* Optional validation function for request body
|
|
20
|
+
*/
|
|
21
|
+
validator?: ValidationFunction<TInput>;
|
|
22
|
+
/**
|
|
23
|
+
* HTTP status code for successful response (default: 200)
|
|
24
|
+
*/
|
|
25
|
+
successCode?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to read JSON body from request (default: true if validator is provided)
|
|
28
|
+
*/
|
|
29
|
+
readBody?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Custom response transformer (default: wraps result in { data: result })
|
|
32
|
+
*/
|
|
33
|
+
responseTransformer?: (result: TOutput) => unknown;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a standardized API handler with validation and error handling
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const createUser = createHandler({
|
|
41
|
+
* handler: async (input, context) => userService.create(input),
|
|
42
|
+
* validator: validateUserCreate,
|
|
43
|
+
* successCode: 201
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function createHandler<TInput = void, TOutput = unknown>(options: HandlerOptions<TInput, TOutput>): (context: RequestContext) => Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a simple handler that doesn't require input validation
|
|
50
|
+
*/
|
|
51
|
+
export declare function createSimpleHandler<TOutput = unknown>(handler: (context: RequestContext) => Promise<TOutput>, options?: {
|
|
52
|
+
successCode?: number;
|
|
53
|
+
responseTransformer?: (result: TOutput) => unknown;
|
|
54
|
+
}): (context: RequestContext) => Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a handler for query parameter-based requests
|
|
57
|
+
*/
|
|
58
|
+
export declare function createQueryHandler<TOutput = unknown>(handler: (context: RequestContext) => Promise<TOutput>, options?: {
|
|
59
|
+
successCode?: number;
|
|
60
|
+
responseTransformer?: (result: TOutput) => unknown;
|
|
61
|
+
}): (context: RequestContext) => Promise<void>;
|
|
62
|
+
//# sourceMappingURL=base-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-handler.d.ts","sourceRoot":"","sources":["../../src/api/base-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,CACjE,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,MAAM,GAAG,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,MAAM,EAAE,OAAO;IAC7C;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE1C;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAEvC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;CACpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO,EAC5D,OAAO,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CA2B5C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAG,OAAO,EACnD,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,EACtD,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;CAAO,GACzF,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAM5C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAG,OAAO,EAClD,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,EACtD,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;CAAO,GACzF,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAQ5C"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { sendJson } from '../utils/http.js';
|
|
2
|
+
import { asyncHandler } from '../infrastructure/errors/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a standardized API handler with validation and error handling
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const createUser = createHandler({
|
|
9
|
+
* handler: async (input, context) => userService.create(input),
|
|
10
|
+
* validator: validateUserCreate,
|
|
11
|
+
* successCode: 201
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function createHandler(options) {
|
|
16
|
+
const { handler, validator, successCode = 200, readBody = Boolean(validator), responseTransformer, } = options;
|
|
17
|
+
return asyncHandler(async (context) => {
|
|
18
|
+
let input;
|
|
19
|
+
if (readBody) {
|
|
20
|
+
const payload = await context.readJsonBody();
|
|
21
|
+
input = validator ? validator(payload) : payload;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
input = undefined;
|
|
25
|
+
}
|
|
26
|
+
const result = await handler(input, context);
|
|
27
|
+
const response = responseTransformer
|
|
28
|
+
? responseTransformer(result)
|
|
29
|
+
: result;
|
|
30
|
+
sendJson(context.res, successCode, response);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a simple handler that doesn't require input validation
|
|
35
|
+
*/
|
|
36
|
+
export function createSimpleHandler(handler, options = {}) {
|
|
37
|
+
return createHandler({
|
|
38
|
+
handler: async (_input, context) => handler(context),
|
|
39
|
+
readBody: false,
|
|
40
|
+
...options,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a handler for query parameter-based requests
|
|
45
|
+
*/
|
|
46
|
+
export function createQueryHandler(handler, options = {}) {
|
|
47
|
+
return asyncHandler(async (context) => {
|
|
48
|
+
const result = await handler(context);
|
|
49
|
+
const response = options.responseTransformer
|
|
50
|
+
? options.responseTransformer(result)
|
|
51
|
+
: result;
|
|
52
|
+
sendJson(context.res, options.successCode || 200, response);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=base-handler.js.map
|