@overlordai/server 1.0.53 → 1.0.55
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/database/migrations/001-init-schema.sql +73 -9
- package/dist/adapters/adapter.interface.d.ts +1 -4
- package/dist/adapters/adapter.interface.d.ts.map +1 -1
- package/dist/adapters/adapter.interface.js.map +1 -1
- package/dist/adapters/adapter.module.d.ts.map +1 -1
- package/dist/adapters/adapter.module.js +8 -7
- package/dist/adapters/adapter.module.js.map +1 -1
- package/dist/adapters/lark/lark-card.builder.d.ts +1 -25
- package/dist/adapters/lark/lark-card.builder.d.ts.map +1 -1
- package/dist/adapters/lark/lark-card.builder.js +6 -110
- package/dist/adapters/lark/lark-card.builder.js.map +1 -1
- package/dist/adapters/lark/lark-message.parser.d.ts +4 -4
- package/dist/adapters/lark/lark-message.parser.d.ts.map +1 -1
- package/dist/adapters/lark/lark-message.parser.js +20 -13
- package/dist/adapters/lark/lark-message.parser.js.map +1 -1
- package/dist/adapters/lark/lark-signature.d.ts.map +1 -1
- package/dist/adapters/lark/lark-signature.js +6 -0
- package/dist/adapters/lark/lark-signature.js.map +1 -1
- package/dist/adapters/lark/lark.adapter.d.ts +14 -9
- package/dist/adapters/lark/lark.adapter.d.ts.map +1 -1
- package/dist/adapters/lark/lark.adapter.js +99 -177
- package/dist/adapters/lark/lark.adapter.js.map +1 -1
- package/dist/adapters/lark/lark.controller.d.ts +10 -1
- package/dist/adapters/lark/lark.controller.d.ts.map +1 -1
- package/dist/adapters/lark/lark.controller.js +48 -14
- package/dist/adapters/lark/lark.controller.js.map +1 -1
- package/dist/adapters/slack/slack-block.builder.d.ts +8 -0
- package/dist/adapters/slack/slack-block.builder.d.ts.map +1 -0
- package/dist/adapters/slack/slack-block.builder.js +117 -0
- package/dist/adapters/slack/slack-block.builder.js.map +1 -0
- package/dist/adapters/slack/slack-message.parser.d.ts +15 -0
- package/dist/adapters/slack/slack-message.parser.d.ts.map +1 -0
- package/dist/adapters/slack/slack-message.parser.js +158 -0
- package/dist/adapters/slack/slack-message.parser.js.map +1 -0
- package/dist/adapters/slack/slack-signature.d.ts +7 -0
- package/dist/adapters/slack/slack-signature.d.ts.map +1 -0
- package/dist/adapters/slack/slack-signature.js +59 -0
- package/dist/adapters/slack/slack-signature.js.map +1 -0
- package/dist/adapters/slack/slack.adapter.d.ts +67 -13
- package/dist/adapters/slack/slack.adapter.d.ts.map +1 -1
- package/dist/adapters/slack/slack.adapter.js +468 -19
- package/dist/adapters/slack/slack.adapter.js.map +1 -1
- package/dist/adapters/slack/slack.controller.d.ts +20 -0
- package/dist/adapters/slack/slack.controller.d.ts.map +1 -0
- package/dist/adapters/slack/slack.controller.js +257 -0
- package/dist/adapters/slack/slack.controller.js.map +1 -0
- package/dist/app.module.d.ts.map +1 -1
- package/dist/app.module.js +4 -0
- package/dist/app.module.js.map +1 -1
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +1 -0
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +4 -5
- package/dist/auth/auth.module.js.map +1 -1
- package/dist/auth/auth.service.d.ts +9 -2
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +50 -79
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/auth/authenticated-request.d.ts +10 -0
- package/dist/auth/authenticated-request.d.ts.map +1 -0
- package/dist/auth/authenticated-request.js +3 -0
- package/dist/auth/authenticated-request.js.map +1 -0
- package/dist/auth/extract-user.middleware.d.ts.map +1 -1
- package/dist/auth/extract-user.middleware.js +2 -1
- package/dist/auth/extract-user.middleware.js.map +1 -1
- package/dist/auth/guards/jwt-auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/jwt-auth.guard.js +5 -2
- package/dist/auth/guards/jwt-auth.guard.js.map +1 -1
- package/dist/auth/guards/project-role.guard.d.ts.map +1 -1
- package/dist/auth/guards/project-role.guard.js +6 -8
- package/dist/auth/guards/project-role.guard.js.map +1 -1
- package/dist/auth/jwt.strategy.d.ts +6 -3
- package/dist/auth/jwt.strategy.d.ts.map +1 -1
- package/dist/auth/jwt.strategy.js +15 -5
- package/dist/auth/jwt.strategy.js.map +1 -1
- package/dist/common/command-parser.d.ts +29 -0
- package/dist/common/command-parser.d.ts.map +1 -0
- package/dist/common/command-parser.js +133 -0
- package/dist/common/command-parser.js.map +1 -0
- package/dist/common/config.d.ts +17 -0
- package/dist/common/config.d.ts.map +1 -0
- package/dist/common/config.js +47 -0
- package/dist/common/config.js.map +1 -0
- package/dist/common/crypto.service.d.ts +4 -1
- package/dist/common/crypto.service.d.ts.map +1 -1
- package/dist/common/crypto.service.js +14 -7
- package/dist/common/crypto.service.js.map +1 -1
- package/dist/common/error-filter.d.ts +1 -0
- package/dist/common/error-filter.d.ts.map +1 -1
- package/dist/common/error-filter.js +6 -2
- package/dist/common/error-filter.js.map +1 -1
- package/dist/common/git-utils.d.ts +9 -0
- package/dist/common/git-utils.d.ts.map +1 -0
- package/dist/common/git-utils.js +41 -0
- package/dist/common/git-utils.js.map +1 -0
- package/dist/common/health.controller.d.ts.map +1 -1
- package/dist/common/health.controller.js +3 -5
- package/dist/common/health.controller.js.map +1 -1
- package/dist/common/machine-utils.d.ts +32 -0
- package/dist/common/machine-utils.d.ts.map +1 -0
- package/dist/common/machine-utils.js +12 -0
- package/dist/common/machine-utils.js.map +1 -0
- package/dist/common/pagination.d.ts +12 -5
- package/dist/common/pagination.d.ts.map +1 -1
- package/dist/common/pagination.js +27 -17
- package/dist/common/pagination.js.map +1 -1
- package/dist/common/project-validation.d.ts +7 -0
- package/dist/common/project-validation.d.ts.map +1 -0
- package/dist/common/project-validation.js +86 -0
- package/dist/common/project-validation.js.map +1 -0
- package/dist/common/rate-limit.guard.d.ts +4 -3
- package/dist/common/rate-limit.guard.d.ts.map +1 -1
- package/dist/common/rate-limit.guard.js +14 -5
- package/dist/common/rate-limit.guard.js.map +1 -1
- package/dist/common/sql-utils.d.ts +6 -0
- package/dist/common/sql-utils.d.ts.map +1 -0
- package/dist/common/sql-utils.js +11 -0
- package/dist/common/sql-utils.js.map +1 -0
- package/dist/common/string-utils.d.ts +6 -0
- package/dist/common/string-utils.d.ts.map +1 -0
- package/dist/common/string-utils.js +15 -0
- package/dist/common/string-utils.js.map +1 -0
- package/dist/common/worker-utils.d.ts +31 -0
- package/dist/common/worker-utils.d.ts.map +1 -0
- package/dist/common/worker-utils.js +12 -0
- package/dist/common/worker-utils.js.map +1 -0
- package/dist/database/base.repository.d.ts +56 -0
- package/dist/database/base.repository.d.ts.map +1 -0
- package/dist/database/base.repository.js +82 -0
- package/dist/database/base.repository.js.map +1 -0
- package/dist/database/database.service.d.ts.map +1 -1
- package/dist/database/database.service.js +9 -1
- package/dist/database/database.service.js.map +1 -1
- package/dist/database/migration-runner.d.ts.map +1 -1
- package/dist/database/migration-runner.js +2 -1
- package/dist/database/migration-runner.js.map +1 -1
- package/dist/database/repositories/audit-log.repository.d.ts.map +1 -1
- package/dist/database/repositories/audit-log.repository.js +16 -18
- package/dist/database/repositories/audit-log.repository.js.map +1 -1
- package/dist/database/repositories/bot.repository.d.ts +18 -32
- package/dist/database/repositories/bot.repository.d.ts.map +1 -1
- package/dist/database/repositories/bot.repository.js +42 -21
- package/dist/database/repositories/bot.repository.js.map +1 -1
- package/dist/database/repositories/developer-token.repository.d.ts +7 -17
- package/dist/database/repositories/developer-token.repository.d.ts.map +1 -1
- package/dist/database/repositories/developer-token.repository.js +24 -15
- package/dist/database/repositories/developer-token.repository.js.map +1 -1
- package/dist/database/repositories/developer.repository.d.ts +5 -1
- package/dist/database/repositories/developer.repository.d.ts.map +1 -1
- package/dist/database/repositories/developer.repository.js +60 -49
- package/dist/database/repositories/developer.repository.js.map +1 -1
- package/dist/database/repositories/machine.repository.d.ts.map +1 -1
- package/dist/database/repositories/machine.repository.js +2 -7
- package/dist/database/repositories/machine.repository.js.map +1 -1
- package/dist/database/repositories/notification.repository.d.ts +1 -0
- package/dist/database/repositories/notification.repository.d.ts.map +1 -1
- package/dist/database/repositories/notification.repository.js +25 -20
- package/dist/database/repositories/notification.repository.js.map +1 -1
- package/dist/database/repositories/project-member.repository.d.ts +7 -16
- package/dist/database/repositories/project-member.repository.d.ts.map +1 -1
- package/dist/database/repositories/project-member.repository.js +34 -24
- package/dist/database/repositories/project-member.repository.js.map +1 -1
- package/dist/database/repositories/project.repository.d.ts +2 -1
- package/dist/database/repositories/project.repository.d.ts.map +1 -1
- package/dist/database/repositories/project.repository.js +70 -71
- package/dist/database/repositories/project.repository.js.map +1 -1
- package/dist/database/repositories/session.repository.d.ts.map +1 -1
- package/dist/database/repositories/session.repository.js +22 -25
- package/dist/database/repositories/session.repository.js.map +1 -1
- package/dist/database/repositories/task.repository.d.ts +31 -7
- package/dist/database/repositories/task.repository.d.ts.map +1 -1
- package/dist/database/repositories/task.repository.js +134 -86
- package/dist/database/repositories/task.repository.js.map +1 -1
- package/dist/database/repositories/worker-token.repository.d.ts.map +1 -1
- package/dist/database/repositories/worker-token.repository.js +18 -16
- package/dist/database/repositories/worker-token.repository.js.map +1 -1
- package/dist/database/repositories/worker.repository.d.ts +50 -0
- package/dist/database/repositories/worker.repository.d.ts.map +1 -0
- package/dist/database/repositories/worker.repository.js +215 -0
- package/dist/database/repositories/worker.repository.js.map +1 -0
- package/dist/database/repositories/workspace.repository.d.ts +3 -2
- package/dist/database/repositories/workspace.repository.d.ts.map +1 -1
- package/dist/database/repositories/workspace.repository.js +29 -21
- package/dist/database/repositories/workspace.repository.js.map +1 -1
- package/dist/database/repository.module.d.ts +3 -0
- package/dist/database/repository.module.d.ts.map +1 -0
- package/dist/database/repository.module.js +45 -0
- package/dist/database/repository.module.js.map +1 -0
- package/dist/dispatcher/capability.service.d.ts +19 -14
- package/dist/dispatcher/capability.service.d.ts.map +1 -1
- package/dist/dispatcher/capability.service.js +77 -69
- package/dist/dispatcher/capability.service.js.map +1 -1
- package/dist/dispatcher/cleanup.service.d.ts +1 -1
- package/dist/dispatcher/cleanup.service.d.ts.map +1 -1
- package/dist/dispatcher/cleanup.service.js +13 -13
- package/dist/dispatcher/cleanup.service.js.map +1 -1
- package/dist/dispatcher/dedup.service.d.ts +17 -3
- package/dist/dispatcher/dedup.service.d.ts.map +1 -1
- package/dist/dispatcher/dedup.service.js +76 -82
- package/dist/dispatcher/dedup.service.js.map +1 -1
- package/dist/dispatcher/dispatcher.module.d.ts.map +1 -1
- package/dist/dispatcher/dispatcher.module.js +11 -18
- package/dist/dispatcher/dispatcher.module.js.map +1 -1
- package/dist/dispatcher/dispatcher.service.d.ts +14 -116
- package/dist/dispatcher/dispatcher.service.d.ts.map +1 -1
- package/dist/dispatcher/dispatcher.service.js +62 -940
- package/dist/dispatcher/dispatcher.service.js.map +1 -1
- package/dist/dispatcher/dispatcher.types.d.ts +33 -0
- package/dist/dispatcher/dispatcher.types.d.ts.map +1 -0
- package/dist/dispatcher/dispatcher.types.js +3 -0
- package/dist/dispatcher/dispatcher.types.js.map +1 -0
- package/dist/dispatcher/heartbeat.service.d.ts +17 -10
- package/dist/dispatcher/heartbeat.service.d.ts.map +1 -1
- package/dist/dispatcher/heartbeat.service.js +47 -51
- package/dist/dispatcher/heartbeat.service.js.map +1 -1
- package/dist/dispatcher/pty-relay.service.d.ts.map +1 -1
- package/dist/dispatcher/pty-relay.service.js +7 -15
- package/dist/dispatcher/pty-relay.service.js.map +1 -1
- package/dist/dispatcher/reconciler.d.ts +18 -8
- package/dist/dispatcher/reconciler.d.ts.map +1 -1
- package/dist/dispatcher/reconciler.js +219 -130
- package/dist/dispatcher/reconciler.js.map +1 -1
- package/dist/dispatcher/scheduler.service.d.ts +15 -9
- package/dist/dispatcher/scheduler.service.d.ts.map +1 -1
- package/dist/dispatcher/scheduler.service.js +95 -53
- package/dist/dispatcher/scheduler.service.js.map +1 -1
- package/dist/dispatcher/state-machine.d.ts.map +1 -1
- package/dist/dispatcher/state-machine.js +1 -5
- package/dist/dispatcher/state-machine.js.map +1 -1
- package/dist/dispatcher/task-creation.service.d.ts +30 -0
- package/dist/dispatcher/task-creation.service.d.ts.map +1 -0
- package/dist/dispatcher/task-creation.service.js +242 -0
- package/dist/dispatcher/task-creation.service.js.map +1 -0
- package/dist/dispatcher/task-lifecycle.service.d.ts +63 -0
- package/dist/dispatcher/task-lifecycle.service.d.ts.map +1 -0
- package/dist/dispatcher/task-lifecycle.service.js +584 -0
- package/dist/dispatcher/task-lifecycle.service.js.map +1 -0
- package/dist/dispatcher/task-log-batcher.d.ts.map +1 -1
- package/dist/dispatcher/task-log-batcher.js +4 -11
- package/dist/dispatcher/task-log-batcher.js.map +1 -1
- package/dist/dispatcher/worker-auth.service.d.ts +29 -0
- package/dist/dispatcher/worker-auth.service.d.ts.map +1 -0
- package/dist/dispatcher/worker-auth.service.js +296 -0
- package/dist/dispatcher/worker-auth.service.js.map +1 -0
- package/dist/dispatcher/worker-connection.manager.d.ts +15 -15
- package/dist/dispatcher/worker-connection.manager.d.ts.map +1 -1
- package/dist/dispatcher/worker-connection.manager.js +35 -43
- package/dist/dispatcher/worker-connection.manager.js.map +1 -1
- package/dist/dispatcher/worker-selector.d.ts +18 -0
- package/dist/dispatcher/worker-selector.d.ts.map +1 -0
- package/dist/dispatcher/worker-selector.js +150 -0
- package/dist/dispatcher/worker-selector.js.map +1 -0
- package/dist/events/event-types.d.ts +31 -0
- package/dist/events/event-types.d.ts.map +1 -0
- package/dist/events/event-types.js +16 -0
- package/dist/events/event-types.js.map +1 -0
- package/dist/events/events.module.d.ts +7 -0
- package/dist/events/events.module.d.ts.map +1 -0
- package/dist/events/events.module.js +26 -0
- package/dist/events/events.module.js.map +1 -0
- package/dist/main.js +22 -0
- package/dist/main.js.map +1 -1
- package/dist/notifier/debouncer.d.ts +1 -1
- package/dist/notifier/debouncer.d.ts.map +1 -1
- package/dist/notifier/debouncer.js +2 -1
- package/dist/notifier/debouncer.js.map +1 -1
- package/dist/notifier/notification-consumer.d.ts +1 -1
- package/dist/notifier/notification-consumer.d.ts.map +1 -1
- package/dist/notifier/notification-consumer.js +5 -5
- package/dist/notifier/notification-consumer.js.map +1 -1
- package/dist/notifier/notifier.module.d.ts.map +1 -1
- package/dist/notifier/notifier.module.js +0 -6
- package/dist/notifier/notifier.module.js.map +1 -1
- package/dist/notifier/notifier.service.d.ts +1 -1
- package/dist/notifier/notifier.service.d.ts.map +1 -1
- package/dist/notifier/notifier.service.js +7 -9
- package/dist/notifier/notifier.service.js.map +1 -1
- package/dist/notifier/template.service.d.ts +1 -1
- package/dist/notifier/template.service.d.ts.map +1 -1
- package/dist/notifier/template.service.js +6 -10
- package/dist/notifier/template.service.js.map +1 -1
- package/dist/redis/redis.service.d.ts.map +1 -1
- package/dist/redis/redis.service.js +2 -2
- package/dist/redis/redis.service.js.map +1 -1
- package/dist/web/admin/admin-audit.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-audit.controller.js +2 -1
- package/dist/web/admin/admin-audit.controller.js.map +1 -1
- package/dist/web/admin/admin-bot.controller.d.ts +11 -48
- package/dist/web/admin/admin-bot.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-bot.controller.js +50 -18
- package/dist/web/admin/admin-bot.controller.js.map +1 -1
- package/dist/web/admin/admin-developer.controller.d.ts +14 -27
- package/dist/web/admin/admin-developer.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-developer.controller.js +62 -28
- package/dist/web/admin/admin-developer.controller.js.map +1 -1
- package/dist/web/admin/admin-machine.controller.d.ts +1 -8
- package/dist/web/admin/admin-machine.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-machine.controller.js +3 -6
- package/dist/web/admin/admin-machine.controller.js.map +1 -1
- package/dist/web/admin/admin-project.controller.d.ts +9 -30
- package/dist/web/admin/admin-project.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-project.controller.js +15 -60
- package/dist/web/admin/admin-project.controller.js.map +1 -1
- package/dist/web/admin/admin-settings.controller.d.ts +7 -10
- package/dist/web/admin/admin-settings.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-settings.controller.js +14 -6
- package/dist/web/admin/admin-settings.controller.js.map +1 -1
- package/dist/web/admin/admin-token.controller.d.ts +6 -13
- package/dist/web/admin/admin-token.controller.d.ts.map +1 -1
- package/dist/web/admin/admin-token.controller.js +15 -27
- package/dist/web/admin/admin-token.controller.js.map +1 -1
- package/dist/web/admin/admin-worker.controller.d.ts +26 -0
- package/dist/web/admin/admin-worker.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-worker.controller.js +184 -0
- package/dist/web/admin/admin-worker.controller.js.map +1 -0
- package/dist/web/dashboard.controller.d.ts +6 -12
- package/dist/web/dashboard.controller.d.ts.map +1 -1
- package/dist/web/dashboard.controller.js +30 -18
- package/dist/web/dashboard.controller.js.map +1 -1
- package/dist/web/dashboard.service.d.ts +21 -12
- package/dist/web/dashboard.service.d.ts.map +1 -1
- package/dist/web/dashboard.service.js +169 -119
- package/dist/web/dashboard.service.js.map +1 -1
- package/dist/web/event.gateway.d.ts +32 -0
- package/dist/web/event.gateway.d.ts.map +1 -0
- package/dist/web/event.gateway.js +168 -0
- package/dist/web/event.gateway.js.map +1 -0
- package/dist/web/frame-handlers/frame-handler.interface.d.ts +24 -0
- package/dist/web/frame-handlers/frame-handler.interface.d.ts.map +1 -0
- package/dist/web/frame-handlers/frame-handler.interface.js +3 -0
- package/dist/web/frame-handlers/frame-handler.interface.js.map +1 -0
- package/dist/web/frame-handlers/frame-handler.registry.d.ts +16 -0
- package/dist/web/frame-handlers/frame-handler.registry.d.ts.map +1 -0
- package/dist/web/frame-handlers/frame-handler.registry.js +39 -0
- package/dist/web/frame-handlers/frame-handler.registry.js.map +1 -0
- package/dist/web/frame-handlers/heartbeat.handler.d.ts +13 -0
- package/dist/web/frame-handlers/heartbeat.handler.d.ts.map +1 -0
- package/dist/web/frame-handlers/heartbeat.handler.js +35 -0
- package/dist/web/frame-handlers/heartbeat.handler.js.map +1 -0
- package/dist/web/frame-handlers/index.d.ts +7 -0
- package/dist/web/frame-handlers/index.d.ts.map +1 -0
- package/dist/web/frame-handlers/index.js +14 -0
- package/dist/web/frame-handlers/index.js.map +1 -0
- package/dist/web/frame-handlers/progress.handler.d.ts +25 -0
- package/dist/web/frame-handlers/progress.handler.d.ts.map +1 -0
- package/dist/web/frame-handlers/progress.handler.js +69 -0
- package/dist/web/frame-handlers/progress.handler.js.map +1 -0
- package/dist/web/frame-handlers/stage-confirm.handler.d.ts +15 -0
- package/dist/web/frame-handlers/stage-confirm.handler.d.ts.map +1 -0
- package/dist/web/frame-handlers/stage-confirm.handler.js +39 -0
- package/dist/web/frame-handlers/stage-confirm.handler.js.map +1 -0
- package/dist/web/frame-handlers/tunnel.handler.d.ts +10 -0
- package/dist/web/frame-handlers/tunnel.handler.d.ts.map +1 -0
- package/dist/web/frame-handlers/tunnel.handler.js +31 -0
- package/dist/web/frame-handlers/tunnel.handler.js.map +1 -0
- package/dist/web/interaction.service.d.ts +0 -4
- package/dist/web/interaction.service.d.ts.map +1 -1
- package/dist/web/interaction.service.js +0 -10
- package/dist/web/interaction.service.js.map +1 -1
- package/dist/web/machine.controller.d.ts +1 -8
- package/dist/web/machine.controller.d.ts.map +1 -1
- package/dist/web/machine.controller.js +6 -9
- package/dist/web/machine.controller.js.map +1 -1
- package/dist/web/notification.controller.d.ts +1 -8
- package/dist/web/notification.controller.d.ts.map +1 -1
- package/dist/web/notification.controller.js +3 -2
- package/dist/web/notification.controller.js.map +1 -1
- package/dist/web/profile.controller.d.ts +19 -10
- package/dist/web/profile.controller.d.ts.map +1 -1
- package/dist/web/profile.controller.js +100 -13
- package/dist/web/profile.controller.js.map +1 -1
- package/dist/web/project-member.service.d.ts +16 -0
- package/dist/web/project-member.service.d.ts.map +1 -0
- package/dist/web/project-member.service.js +90 -0
- package/dist/web/project-member.service.js.map +1 -0
- package/dist/web/project.controller.d.ts +43 -26
- package/dist/web/project.controller.d.ts.map +1 -1
- package/dist/web/project.controller.js +73 -46
- package/dist/web/project.controller.js.map +1 -1
- package/dist/web/pty.gateway.d.ts +9 -3
- package/dist/web/pty.gateway.d.ts.map +1 -1
- package/dist/web/pty.gateway.js +46 -18
- package/dist/web/pty.gateway.js.map +1 -1
- package/dist/web/search.service.d.ts +9 -2
- package/dist/web/search.service.d.ts.map +1 -1
- package/dist/web/search.service.js +53 -26
- package/dist/web/search.service.js.map +1 -1
- package/dist/web/task.controller.d.ts +15 -24
- package/dist/web/task.controller.d.ts.map +1 -1
- package/dist/web/task.controller.js +70 -53
- package/dist/web/task.controller.js.map +1 -1
- package/dist/web/tunnel.service.d.ts +74 -0
- package/dist/web/tunnel.service.d.ts.map +1 -0
- package/dist/web/tunnel.service.js +250 -0
- package/dist/web/tunnel.service.js.map +1 -0
- package/dist/web/web-event.service.d.ts +25 -0
- package/dist/web/web-event.service.d.ts.map +1 -0
- package/dist/web/web-event.service.js +116 -0
- package/dist/web/web-event.service.js.map +1 -0
- package/dist/web/web.module.d.ts.map +1 -1
- package/dist/web/web.module.js +13 -28
- package/dist/web/web.module.js.map +1 -1
- package/dist/web/worker-channel.gateway.d.ts +10 -18
- package/dist/web/worker-channel.gateway.d.ts.map +1 -1
- package/dist/web/worker-channel.gateway.js +70 -144
- package/dist/web/worker-channel.gateway.js.map +1 -1
- package/dist/web/worker-web.controller.d.ts +15 -0
- package/dist/web/worker-web.controller.d.ts.map +1 -0
- package/dist/web/worker-web.controller.js +143 -0
- package/dist/web/worker-web.controller.js.map +1 -0
- package/dist/web/worker.controller.d.ts +3 -3
- package/dist/web/worker.controller.d.ts.map +1 -1
- package/dist/web/worker.controller.js +8 -8
- package/dist/web/worker.controller.js.map +1 -1
- package/dist/web/workspace.controller.d.ts +8 -33
- package/dist/web/workspace.controller.d.ts.map +1 -1
- package/dist/web/workspace.controller.js +93 -205
- package/dist/web/workspace.controller.js.map +1 -1
- package/package.json +10 -2
- package/public/apple-touch-icon-120x120.png +0 -0
- package/public/apple-touch-icon-152x152.png +0 -0
- package/public/apple-touch-icon-180x180.png +0 -0
- package/public/assets/AccessTokensPage-DPQB2fbi.js +1 -0
- package/public/assets/AdminPage-BqVelYNu.js +1 -0
- package/public/assets/ApiReferencePage-CiGvbLxL.js +1 -0
- package/public/assets/AuditLogPage-DSo4jVYm.js +6 -0
- package/public/assets/BindPlatformPage-CTqzpOmt.js +1 -0
- package/public/assets/BotManage-CIR0rrK7.js +6 -0
- package/public/assets/CliReferencePage-C8GmlwUz.js +14 -0
- package/public/assets/DeveloperManage-r6y2AoB4.js +16 -0
- package/public/assets/EditProjectPage-7WCsNltj.js +2 -0
- package/public/assets/{EmptyState-CvmhFgWJ.js → EmptyState-D3foEiul.js} +1 -1
- package/public/assets/HomePage-D4yv4orb.js +1 -0
- package/public/assets/InfoRow-DhdTYoY9.js +1 -0
- package/public/assets/LandingPage-CqS0E2eC.js +43 -0
- package/public/assets/LoginPage-DDXkdcz_.js +1 -0
- package/public/assets/MetricBar-DMMHfS0A.js +1 -0
- package/public/assets/{NotFoundPage-BuiAS4g4.js → NotFoundPage-D5x5BrlX.js} +1 -1
- package/public/assets/OnboardingGuide-D8RyPcEd.js +1 -0
- package/public/assets/PipelineEditorPage-y2-Q8ofQ.js +3 -0
- package/public/assets/ProfilePage-DN7usHOi.js +1 -0
- package/public/assets/ProjectDetailPage-DJexg49z.js +7 -0
- package/public/assets/ProjectListPage-Bz7I2D0H.js +6 -0
- package/public/assets/QuickAuth-Dr0Q50ld.js +1 -0
- package/public/assets/{RemoveMemberConfirmDialog-DS9z6jQT.js → RemoveMemberConfirmDialog-BCrue0AP.js} +2 -2
- package/public/assets/Select-BnV8yZlD.js +6 -0
- package/public/assets/SettingsPage-HaUCcsgl.js +6 -0
- package/public/assets/{Skeleton-CcVqz28_.js → Skeleton-DUgWc2LJ.js} +1 -1
- package/public/assets/SkillPage-BInwZTQh.js +1 -0
- package/public/assets/TaskDetailPage-CfwEj1hy.js +31 -0
- package/public/assets/TaskListPage-Dh59ldSZ.js +1 -0
- package/public/assets/TaskStatusBadge-DuOoGIwE.js +1 -0
- package/public/assets/TerminalHomePage-BwXJjr-a.js +16 -0
- package/public/assets/TokenManage-B0Cpv6SO.js +1 -0
- package/public/assets/TotpSetupPage-MSCCURj9.js +9 -0
- package/public/assets/WorkerDetailPage-R2veIzKo.js +1 -0
- package/public/assets/WorkerListPage-CserMjGO.js +6 -0
- package/public/assets/WorkerSetupGuidePage-SqO2lzVa.js +11 -0
- package/public/assets/{arrow-left-CVKez32c.js → arrow-left-DklRsENx.js} +1 -1
- package/public/assets/{arrow-right-g7hTftEi.js → arrow-right-MDrzFe3K.js} +1 -1
- package/public/assets/{bot-DYvBcsZn.js → bot-DPaziJPf.js} +1 -1
- package/public/assets/{chevron-right-COxU2yxz.js → chevron-right-CqyufMDW.js} +1 -1
- package/public/assets/{copy-BGttVgA1.js → copy-BUH7P2Hf.js} +1 -1
- package/public/assets/date-BdNtiQTP.js +1 -0
- package/public/assets/{external-link-DXlCfUjE.js → external-link-ChPgQ7N_.js} +1 -1
- package/public/assets/index-BS0Fbx5V.css +1 -0
- package/public/assets/index-vL7aQJNr.js +225 -0
- package/public/assets/{key-3eDVdGih.js → key-CxvwwHnW.js} +1 -1
- package/public/assets/{loader-circle-DPm92ETj.js → loader-circle-DS5g1-Od.js} +1 -1
- package/public/assets/password-CHk45-jw.js +1 -0
- package/public/assets/{pencil-Bs3PwH2W.js → pencil-B6spIBcw.js} +1 -1
- package/public/assets/{plus-d-PLzbVX.js → plus-Bnd1Vz2Y.js} +1 -1
- package/public/assets/{rotate-ccw-Cus8CABi.js → rotate-ccw-CgcLAXNR.js} +1 -1
- package/public/assets/{scroll-text-CV3wlIy2.js → scroll-text-CecZ0Fk5.js} +1 -1
- package/public/assets/{settings-Ccijf48b.js → settings-C1uOD3PZ.js} +1 -1
- package/public/assets/status-colors-BPEUp90-.js +1 -0
- package/public/assets/string-B39tzdVK.js +1 -0
- package/public/assets/task-constants-BbFyCyKk.js +14 -0
- package/public/assets/task.store-BE6fEPu4.js +1 -0
- package/public/assets/{trash-2-bRJ-xwtq.js → trash-2-A2FsT1yG.js} +1 -1
- package/public/assets/useFetch-vGZMAvGi.js +1 -0
- package/public/assets/{users-LNQqKSEN.js → users-CEdRS_A3.js} +1 -1
- package/public/assets/wifi-D60NkK6F.js +6 -0
- package/public/assets/zap-DXw1NrWz.js +6 -0
- package/public/icon-192x192.png +0 -0
- package/public/icon-512x512.png +0 -0
- package/public/icon-maskable-192x192.png +0 -0
- package/public/icon-maskable-512x512.png +0 -0
- package/public/index.html +21 -4
- package/public/manifest.webmanifest +1 -0
- package/public/og-image.png +0 -0
- package/public/registerSW.js +1 -0
- package/public/sw.js +1 -0
- package/public/workbox-6e9b121d.js +1 -0
- package/database/migrations/002-add-indexes.sql +0 -17
- package/database/migrations/003-add-settings-table.sql +0 -4
- package/database/migrations/004-add-developer-id-index.sql +0 -5
- package/database/migrations/005-add-worker-version.sql +0 -2
- package/database/migrations/006-add-decommission-fields.sql +0 -2
- package/database/migrations/007-add-ssh-url.sql +0 -1
- package/public/assets/AccessTokensPage-Cb5hGBfN.js +0 -1
- package/public/assets/AdminPage-C7Xytkfo.js +0 -1
- package/public/assets/ApiReferencePage-DLGVc4xN.js +0 -1
- package/public/assets/AuditLogPage-BgqsUJ7x.js +0 -6
- package/public/assets/BotManage-Ds9DYQZA.js +0 -6
- package/public/assets/CliReferencePage-WXinn_69.js +0 -8
- package/public/assets/DeveloperManage-saSq3Hfx.js +0 -16
- package/public/assets/EditProjectPage-C4xWYLTo.js +0 -2
- package/public/assets/HomePage-y20pQ52r.js +0 -1
- package/public/assets/LandingPage-CB5BBbdI.js +0 -36
- package/public/assets/LoginPage-DLljhJkQ.js +0 -1
- package/public/assets/MachineDetailPage-CPm9tfdp.js +0 -1
- package/public/assets/MachineListPage-D-nhVz-m.js +0 -6
- package/public/assets/PipelineEditorPage-B9GgqAju.js +0 -3
- package/public/assets/ProfilePage-DASpeJq6.js +0 -1
- package/public/assets/ProjectDetailPage-DWZyNwTV.js +0 -7
- package/public/assets/ProjectListPage-BUMX3Dxa.js +0 -6
- package/public/assets/QuickAuth-B9mvq7ht.js +0 -1
- package/public/assets/Select-A7PXobk_.js +0 -6
- package/public/assets/SettingsPage-WGzxUbGp.js +0 -6
- package/public/assets/SkillPage-BIt2kF3W.js +0 -1
- package/public/assets/TaskDetailPage-CePyNfp6.js +0 -44
- package/public/assets/TaskListPage-MO4_PSve.js +0 -1
- package/public/assets/TaskStatusBadge-QtQUDscM.js +0 -1
- package/public/assets/TokenManage-Sf0RGymw.js +0 -1
- package/public/assets/TotpSetupPage-D-rbEYLf.js +0 -9
- package/public/assets/WorkerSetupGuidePage-D6Fv1MQo.js +0 -16
- package/public/assets/index-CDBuOPx4.js +0 -212
- package/public/assets/index-CQojj7Zu.css +0 -1
- package/public/assets/protocol-C5uQmiiB.js +0 -1
- package/public/assets/task.store-CvjSr507.js +0 -1
- /package/public/assets/{TaskDetailPage-Beg8tuEN.css → task-constants-Beg8tuEN.css} +0 -0
|
@@ -44,38 +44,79 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
44
44
|
var Reconciler_1;
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
46
|
exports.Reconciler = void 0;
|
|
47
|
+
const protocol_1 = require("@overlordai/protocol");
|
|
47
48
|
const common_1 = require("@nestjs/common");
|
|
48
49
|
const crypto = __importStar(require("node:crypto"));
|
|
49
|
-
const protocol_1 = require("@overlordai/protocol");
|
|
50
50
|
const task_repository_1 = require("../database/repositories/task.repository");
|
|
51
|
-
const
|
|
51
|
+
const worker_repository_1 = require("../database/repositories/worker.repository");
|
|
52
52
|
const audit_log_repository_1 = require("../database/repositories/audit-log.repository");
|
|
53
53
|
const workspace_repository_1 = require("../database/repositories/workspace.repository");
|
|
54
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
55
|
+
const event_types_1 = require("../events/event-types");
|
|
54
56
|
const scheduler_service_1 = require("./scheduler.service");
|
|
55
57
|
const cleanup_service_1 = require("./cleanup.service");
|
|
56
58
|
const worker_connection_manager_1 = require("./worker-connection.manager");
|
|
57
|
-
let Reconciler =
|
|
59
|
+
let Reconciler = class Reconciler {
|
|
60
|
+
static { Reconciler_1 = this; }
|
|
58
61
|
taskRepo;
|
|
59
|
-
|
|
62
|
+
workerRepo;
|
|
60
63
|
auditLogRepo;
|
|
61
64
|
workspaceRepo;
|
|
62
65
|
schedulerService;
|
|
63
66
|
cleanupService;
|
|
64
67
|
workerConnectionManager;
|
|
68
|
+
eventEmitter;
|
|
65
69
|
logger = new common_1.Logger(Reconciler_1.name);
|
|
66
|
-
|
|
70
|
+
failedCleanups = new Map();
|
|
71
|
+
cleanupRetryTimer = null;
|
|
72
|
+
static CLEANUP_RETRY_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
73
|
+
constructor(taskRepo, workerRepo, auditLogRepo, workspaceRepo, schedulerService, cleanupService, workerConnectionManager, eventEmitter) {
|
|
67
74
|
this.taskRepo = taskRepo;
|
|
68
|
-
this.
|
|
75
|
+
this.workerRepo = workerRepo;
|
|
69
76
|
this.auditLogRepo = auditLogRepo;
|
|
70
77
|
this.workspaceRepo = workspaceRepo;
|
|
71
78
|
this.schedulerService = schedulerService;
|
|
72
79
|
this.cleanupService = cleanupService;
|
|
73
80
|
this.workerConnectionManager = workerConnectionManager;
|
|
81
|
+
this.eventEmitter = eventEmitter;
|
|
74
82
|
}
|
|
75
83
|
async onModuleInit() {
|
|
76
84
|
this.logger.log('Running boot reconciliation...');
|
|
77
85
|
await this.onBoot();
|
|
78
86
|
this.logger.log('Boot reconciliation complete');
|
|
87
|
+
this.startCleanupRetryLoop();
|
|
88
|
+
}
|
|
89
|
+
onModuleDestroy() {
|
|
90
|
+
if (this.cleanupRetryTimer) {
|
|
91
|
+
clearInterval(this.cleanupRetryTimer);
|
|
92
|
+
this.cleanupRetryTimer = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
startCleanupRetryLoop() {
|
|
96
|
+
this.cleanupRetryTimer = setInterval(() => {
|
|
97
|
+
void this.retryFailedCleanups();
|
|
98
|
+
}, Reconciler_1.CLEANUP_RETRY_INTERVAL_MS);
|
|
99
|
+
}
|
|
100
|
+
async retryFailedCleanups() {
|
|
101
|
+
if (this.failedCleanups.size === 0)
|
|
102
|
+
return;
|
|
103
|
+
this.logger.log(`Retrying ${this.failedCleanups.size} failed workspace cleanup(s)...`);
|
|
104
|
+
const entries = [...this.failedCleanups.entries()];
|
|
105
|
+
for (const [key, entry] of entries) {
|
|
106
|
+
const workspace = this.workspaceRepo.findByTaskId(entry.taskId);
|
|
107
|
+
if (!workspace) {
|
|
108
|
+
this.failedCleanups.delete(key);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
await this.cleanupService.scheduleCleanup(entry.taskId, entry.workerId, workspace.path);
|
|
113
|
+
this.failedCleanups.delete(key);
|
|
114
|
+
this.logger.log(`Successfully retried cleanup for task #${entry.taskId}`);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
this.logger.error(`Retry cleanup still failing for task #${entry.taskId}: ${(0, protocol_1.getErrorMessage)(err)}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
79
120
|
}
|
|
80
121
|
// ---------------------------------------------------------------------------
|
|
81
122
|
// onBoot — startup reconciliation
|
|
@@ -84,99 +125,137 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
84
125
|
const now = Date.now();
|
|
85
126
|
let reEnqueuedCount = 0;
|
|
86
127
|
let failedStaleCount = 0;
|
|
128
|
+
// Single query to fetch all active tasks instead of 4 separate findByStatus calls
|
|
129
|
+
const allActiveTasks = this.taskRepo.findByStatus([
|
|
130
|
+
protocol_1.TaskStatus.QUEUED,
|
|
131
|
+
protocol_1.TaskStatus.ASSIGNED,
|
|
132
|
+
protocol_1.TaskStatus.RUNNING,
|
|
133
|
+
protocol_1.TaskStatus.SUSPENDED,
|
|
134
|
+
]);
|
|
135
|
+
// Group tasks by status in memory
|
|
136
|
+
const queuedTasks = [];
|
|
137
|
+
const assignedTasks = [];
|
|
138
|
+
const runningTasks = [];
|
|
139
|
+
const suspendedTasks = [];
|
|
140
|
+
for (const task of allActiveTasks) {
|
|
141
|
+
switch (task.status) {
|
|
142
|
+
case protocol_1.TaskStatus.QUEUED:
|
|
143
|
+
queuedTasks.push(task);
|
|
144
|
+
break;
|
|
145
|
+
case protocol_1.TaskStatus.ASSIGNED:
|
|
146
|
+
assignedTasks.push(task);
|
|
147
|
+
break;
|
|
148
|
+
case protocol_1.TaskStatus.RUNNING:
|
|
149
|
+
runningTasks.push(task);
|
|
150
|
+
break;
|
|
151
|
+
case protocol_1.TaskStatus.SUSPENDED:
|
|
152
|
+
suspendedTasks.push(task);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Pre-fetch all referenced workers in a single batch lookup
|
|
157
|
+
const workerIds = new Set();
|
|
158
|
+
for (const task of allActiveTasks) {
|
|
159
|
+
if (task.workerId)
|
|
160
|
+
workerIds.add(task.workerId);
|
|
161
|
+
}
|
|
162
|
+
const workerCache = new Map();
|
|
163
|
+
for (const wid of workerIds) {
|
|
164
|
+
workerCache.set(wid, this.workerRepo.findById(wid));
|
|
165
|
+
}
|
|
87
166
|
// Step 1: Re-enqueue QUEUED/ASSIGNED tasks missing from BullMQ.
|
|
88
167
|
// On boot we conservatively re-enqueue all QUEUED tasks since BullMQ
|
|
89
168
|
// may have lost state during a restart.
|
|
90
|
-
const queuedTasks = this.taskRepo.findByStatus([protocol_1.TaskStatus.QUEUED]);
|
|
91
169
|
for (const task of queuedTasks) {
|
|
92
170
|
await this.schedulerService.enqueueTask(task.id);
|
|
93
171
|
reEnqueuedCount++;
|
|
94
172
|
this.logger.log(`Re-enqueued QUEUED task #${task.id}`);
|
|
95
173
|
}
|
|
96
|
-
// ASSIGNED tasks with offline/missing
|
|
97
|
-
const assignedTasks = this.taskRepo.findByStatus([protocol_1.TaskStatus.ASSIGNED]);
|
|
174
|
+
// ASSIGNED tasks with offline/missing workers get reset to QUEUED
|
|
98
175
|
for (const task of assignedTasks) {
|
|
99
|
-
if (task.
|
|
100
|
-
const
|
|
101
|
-
if (this.
|
|
176
|
+
if (task.workerId) {
|
|
177
|
+
const worker = workerCache.get(task.workerId) ?? null;
|
|
178
|
+
if (this.isWorkerUnavailable(worker)) {
|
|
102
179
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.QUEUED, task.revision, {
|
|
103
|
-
|
|
180
|
+
workerId: null,
|
|
104
181
|
assignedAt: null,
|
|
105
182
|
});
|
|
106
183
|
await this.schedulerService.enqueueTask(task.id);
|
|
107
184
|
reEnqueuedCount++;
|
|
108
|
-
this.logger.warn(`Reset ASSIGNED task #${task.id} to QUEUED (
|
|
185
|
+
this.logger.warn(`Reset ASSIGNED task #${task.id} to QUEUED (worker ${task.workerId} offline)`);
|
|
109
186
|
}
|
|
110
187
|
else {
|
|
111
|
-
//
|
|
188
|
+
// Worker online — re-enqueue so the scheduler can verify and re-dispatch
|
|
112
189
|
await this.schedulerService.enqueueTask(task.id);
|
|
113
190
|
reEnqueuedCount++;
|
|
114
191
|
}
|
|
115
192
|
}
|
|
116
193
|
else {
|
|
117
|
-
// No
|
|
194
|
+
// No worker assigned — reset to QUEUED
|
|
118
195
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.QUEUED, task.revision);
|
|
119
196
|
await this.schedulerService.enqueueTask(task.id);
|
|
120
197
|
reEnqueuedCount++;
|
|
121
198
|
}
|
|
122
199
|
}
|
|
123
200
|
// Step 2: Fail stale RUNNING/SUSPENDED tasks (grace 10 min).
|
|
124
|
-
const runningTasks = this.taskRepo.findByStatus([protocol_1.TaskStatus.RUNNING]);
|
|
125
201
|
for (const task of runningTasks) {
|
|
126
|
-
if (!task.
|
|
202
|
+
if (!task.workerId) {
|
|
127
203
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
128
|
-
errorMessage: 'No
|
|
204
|
+
errorMessage: 'No worker assigned during boot reconciliation',
|
|
129
205
|
completedAt: new Date().toISOString(),
|
|
130
206
|
});
|
|
207
|
+
this.emitTaskStatusChanged(task.id, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
131
208
|
failedStaleCount++;
|
|
132
209
|
continue;
|
|
133
210
|
}
|
|
134
|
-
const
|
|
135
|
-
if (this.
|
|
136
|
-
const lastHeartbeat =
|
|
137
|
-
? new Date(
|
|
211
|
+
const worker = workerCache.get(task.workerId) ?? null;
|
|
212
|
+
if (this.isWorkerUnavailable(worker)) {
|
|
213
|
+
const lastHeartbeat = worker?.lastHeartbeat
|
|
214
|
+
? new Date(worker.lastHeartbeat).getTime()
|
|
138
215
|
: 0;
|
|
139
216
|
if (now - lastHeartbeat > protocol_1.GRACE_WINDOW_MS) {
|
|
140
217
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
141
|
-
errorMessage: `
|
|
218
|
+
errorMessage: `Worker '${worker?.name ?? task.workerId}' offline beyond grace window (${Math.round((now - lastHeartbeat) / 1000)}s)`,
|
|
142
219
|
completedAt: new Date().toISOString(),
|
|
143
220
|
});
|
|
144
|
-
|
|
145
|
-
|
|
221
|
+
this.emitTaskStatusChanged(task.id, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
222
|
+
if (task.workerId)
|
|
223
|
+
this.scheduleWorkspaceCleanup(task.id, task.workerId);
|
|
146
224
|
failedStaleCount++;
|
|
147
|
-
this.logger.warn(`Failed stale RUNNING task #${task.id} (
|
|
225
|
+
this.logger.warn(`Failed stale RUNNING task #${task.id} (worker ${task.workerId} offline > ${protocol_1.GRACE_WINDOW_MS / 1000}s)`);
|
|
148
226
|
}
|
|
149
227
|
else {
|
|
150
228
|
// Within grace window: suspend and await Worker recovery
|
|
151
229
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.SUSPENDED, task.revision);
|
|
152
|
-
this.logger.warn(`Suspended RUNNING task #${task.id} (
|
|
230
|
+
this.logger.warn(`Suspended RUNNING task #${task.id} (worker ${task.workerId} offline, within grace window)`);
|
|
153
231
|
}
|
|
154
232
|
}
|
|
155
233
|
}
|
|
156
|
-
const suspendedTasks = this.taskRepo.findByStatus([protocol_1.TaskStatus.SUSPENDED]);
|
|
157
234
|
for (const task of suspendedTasks) {
|
|
158
|
-
if (!task.
|
|
235
|
+
if (!task.workerId) {
|
|
159
236
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
160
|
-
errorMessage: 'No
|
|
237
|
+
errorMessage: 'No worker assigned during boot reconciliation',
|
|
161
238
|
completedAt: new Date().toISOString(),
|
|
162
239
|
});
|
|
240
|
+
this.emitTaskStatusChanged(task.id, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
163
241
|
failedStaleCount++;
|
|
164
242
|
continue;
|
|
165
243
|
}
|
|
166
|
-
const
|
|
167
|
-
if (this.
|
|
168
|
-
const lastHeartbeat =
|
|
169
|
-
? new Date(
|
|
244
|
+
const worker = workerCache.get(task.workerId) ?? null;
|
|
245
|
+
if (this.isWorkerUnavailable(worker)) {
|
|
246
|
+
const lastHeartbeat = worker?.lastHeartbeat
|
|
247
|
+
? new Date(worker.lastHeartbeat).getTime()
|
|
170
248
|
: 0;
|
|
171
249
|
if (now - lastHeartbeat > protocol_1.GRACE_WINDOW_MS) {
|
|
172
250
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
173
|
-
errorMessage: `
|
|
251
|
+
errorMessage: `Worker '${worker?.name ?? task.workerId}' offline beyond grace window`,
|
|
174
252
|
completedAt: new Date().toISOString(),
|
|
175
253
|
});
|
|
176
|
-
|
|
177
|
-
|
|
254
|
+
this.emitTaskStatusChanged(task.id, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
255
|
+
if (task.workerId)
|
|
256
|
+
this.scheduleWorkspaceCleanup(task.id, task.workerId);
|
|
178
257
|
failedStaleCount++;
|
|
179
|
-
this.logger.warn(`Failed stale SUSPENDED task #${task.id} (
|
|
258
|
+
this.logger.warn(`Failed stale SUSPENDED task #${task.id} (worker ${task.workerId} offline > grace)`);
|
|
180
259
|
}
|
|
181
260
|
// Within grace: keep SUSPENDED, await Worker recovery
|
|
182
261
|
}
|
|
@@ -184,13 +263,13 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
184
263
|
// Step 3: Remove stale BullMQ jobs for terminal tasks.
|
|
185
264
|
// BullMQ removeOnComplete/removeOnFail handles most cleanup.
|
|
186
265
|
// The scheduler's processJob re-checks status and skips stale tasks.
|
|
187
|
-
// Step 4: Recalculate active_slots for all
|
|
188
|
-
const
|
|
189
|
-
for (const
|
|
190
|
-
const actualSlots = this.
|
|
191
|
-
if (
|
|
192
|
-
this.
|
|
193
|
-
this.logger.log(`
|
|
266
|
+
// Step 4: Recalculate active_slots for all workers and update DB if mismatched.
|
|
267
|
+
const allWorkers = this.workerRepo.findAll();
|
|
268
|
+
for (const worker of allWorkers) {
|
|
269
|
+
const actualSlots = this.workerRepo.countActiveSlots(worker.id);
|
|
270
|
+
if (worker.activeSlots !== actualSlots) {
|
|
271
|
+
this.workerRepo.updateActiveSlots(worker.id, actualSlots);
|
|
272
|
+
this.logger.log(`Worker '${worker.name}' active_slots corrected: ${worker.activeSlots} → ${actualSlots}`);
|
|
194
273
|
}
|
|
195
274
|
}
|
|
196
275
|
// Step 5: Write audit_log.
|
|
@@ -202,7 +281,7 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
202
281
|
reEnqueued: reEnqueuedCount,
|
|
203
282
|
failedStale: failedStaleCount,
|
|
204
283
|
globalActiveCount,
|
|
205
|
-
|
|
284
|
+
workersChecked: allWorkers.length,
|
|
206
285
|
}),
|
|
207
286
|
});
|
|
208
287
|
// Step 6 (branch g): Re-enqueue cleanup for terminal tasks with active workspaces.
|
|
@@ -212,12 +291,12 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
212
291
|
let cleanupReEnqueuedCount = 0;
|
|
213
292
|
for (const workspace of orphanedWorkspaces) {
|
|
214
293
|
try {
|
|
215
|
-
await this.cleanupService.scheduleCleanup(workspace.taskId, workspace.
|
|
294
|
+
await this.cleanupService.scheduleCleanup(workspace.taskId, workspace.workerId, workspace.path, 0);
|
|
216
295
|
cleanupReEnqueuedCount++;
|
|
217
|
-
this.logger.warn(`Re-enqueued cleanup for workspace #${workspace.id} (task #${workspace.taskId},
|
|
296
|
+
this.logger.warn(`Re-enqueued cleanup for workspace #${workspace.id} (task #${workspace.taskId}, worker ${workspace.workerId})`);
|
|
218
297
|
}
|
|
219
298
|
catch (err) {
|
|
220
|
-
this.logger.error(`Failed to re-enqueue cleanup for workspace #${workspace.id} (task #${workspace.taskId}): ${
|
|
299
|
+
this.logger.error(`Failed to re-enqueue cleanup for workspace #${workspace.id} (task #${workspace.taskId}): ${(0, protocol_1.getErrorMessage)(err)}`);
|
|
221
300
|
}
|
|
222
301
|
}
|
|
223
302
|
this.logger.log(`Boot reconciliation: re-enqueued=${reEnqueuedCount}, failed_stale=${failedStaleCount}, active_tasks=${globalActiveCount}, cleanup_re-enqueued=${cleanupReEnqueuedCount}`);
|
|
@@ -233,32 +312,32 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
233
312
|
// e. CANCELLED → notify Worker stop
|
|
234
313
|
// f. Not reported → FAILED
|
|
235
314
|
// ---------------------------------------------------------------------------
|
|
236
|
-
async handleReconnect(
|
|
237
|
-
this.logger.log(`Reconciling reconnect for
|
|
238
|
-
const
|
|
239
|
-
if (!
|
|
240
|
-
this.logger.warn(`Reconnect from unknown
|
|
315
|
+
async handleReconnect(workerId, tasks) {
|
|
316
|
+
this.logger.log(`Reconciling reconnect for worker ${workerId} with ${tasks.length} reported task(s)`);
|
|
317
|
+
const worker = this.workerRepo.findById(workerId);
|
|
318
|
+
if (!worker) {
|
|
319
|
+
this.logger.warn(`Reconnect from unknown worker ${workerId}, ignoring`);
|
|
241
320
|
return [];
|
|
242
321
|
}
|
|
243
322
|
const actions = [];
|
|
244
323
|
const reportedTaskIds = new Set(tasks.map((t) => t.taskId));
|
|
245
324
|
const reportedTaskMap = new Map(tasks.map((t) => [t.taskId, t]));
|
|
246
|
-
// Get all tasks assigned to this
|
|
247
|
-
const
|
|
325
|
+
// Get all tasks assigned to this worker in active or recent terminal states
|
|
326
|
+
const activeWorkerTasks = this.taskRepo.findByWorkerId(workerId, [
|
|
248
327
|
protocol_1.TaskStatus.RUNNING,
|
|
249
328
|
protocol_1.TaskStatus.SUSPENDED,
|
|
250
329
|
protocol_1.TaskStatus.ASSIGNED,
|
|
251
330
|
]);
|
|
252
|
-
const
|
|
331
|
+
const terminalWorkerTasks = this.taskRepo.findByWorkerId(workerId, [
|
|
253
332
|
protocol_1.TaskStatus.FAILED,
|
|
254
333
|
protocol_1.TaskStatus.CANCELLED,
|
|
255
334
|
]);
|
|
256
|
-
const
|
|
257
|
-
// Process each
|
|
258
|
-
for (const task of
|
|
335
|
+
const allWorkerTasks = [...activeWorkerTasks, ...terminalWorkerTasks];
|
|
336
|
+
// Process each worker task against the Worker's report
|
|
337
|
+
for (const task of allWorkerTasks) {
|
|
259
338
|
const reported = reportedTaskMap.get(task.id);
|
|
260
339
|
if (reported) {
|
|
261
|
-
const action = this.reconcileReportedTask(
|
|
340
|
+
const action = this.reconcileReportedTask(worker, task, reported);
|
|
262
341
|
actions.push({ taskId: task.id, action });
|
|
263
342
|
}
|
|
264
343
|
else if (task.status === protocol_1.TaskStatus.RUNNING ||
|
|
@@ -266,15 +345,16 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
266
345
|
// Branch (f): Dispatcher has task but Worker did not report it.
|
|
267
346
|
// Worker lost execution context (process exited / Worker restarted).
|
|
268
347
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
269
|
-
errorMessage: `Worker '${
|
|
348
|
+
errorMessage: `Worker '${worker.name}' reconnected but did not report this task (execution context lost)`,
|
|
270
349
|
completedAt: new Date().toISOString(),
|
|
271
350
|
});
|
|
272
|
-
if (task.
|
|
273
|
-
this.scheduleWorkspaceCleanup(task.id, task.
|
|
351
|
+
if (task.workerId)
|
|
352
|
+
this.scheduleWorkspaceCleanup(task.id, task.workerId);
|
|
353
|
+
this.emitTaskStatusChanged(task.id, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
274
354
|
this.auditLogRepo.create({
|
|
275
355
|
action: 'reconcile_unreported_failed',
|
|
276
356
|
resource: `task:${task.id}`,
|
|
277
|
-
detail: `Task not reported by Worker '${
|
|
357
|
+
detail: `Task not reported by Worker '${worker.name}' during reconnect`,
|
|
278
358
|
});
|
|
279
359
|
actions.push({ taskId: task.id, action: 'failed_unreported' });
|
|
280
360
|
this.logger.warn(`Task #${task.id} (${task.status}) not reported by Worker, marked FAILED`);
|
|
@@ -282,7 +362,7 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
282
362
|
else if (task.status === protocol_1.TaskStatus.ASSIGNED) {
|
|
283
363
|
// ASSIGNED but not reported — reset to QUEUED for rescheduling
|
|
284
364
|
this.updateTaskStatusSafe(task.id, protocol_1.TaskStatus.QUEUED, task.revision, {
|
|
285
|
-
|
|
365
|
+
workerId: null,
|
|
286
366
|
assignedAt: null,
|
|
287
367
|
});
|
|
288
368
|
await this.schedulerService.enqueueTask(task.id);
|
|
@@ -290,34 +370,34 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
290
370
|
this.logger.warn(`Task #${task.id} (ASSIGNED) not reported by Worker, reset to QUEUED`);
|
|
291
371
|
}
|
|
292
372
|
}
|
|
293
|
-
// Handle tasks reported by Worker that Dispatcher doesn't have on this
|
|
373
|
+
// Handle tasks reported by Worker that Dispatcher doesn't have on this worker
|
|
294
374
|
for (const reported of tasks) {
|
|
295
|
-
if (
|
|
375
|
+
if (allWorkerTasks.some((t) => t.id === reported.taskId))
|
|
296
376
|
continue;
|
|
297
377
|
const task = this.taskRepo.findById(reported.taskId);
|
|
298
378
|
if (!task) {
|
|
299
379
|
this.logger.warn(`Worker reported unknown task #${reported.taskId}, requesting cleanup`);
|
|
300
|
-
this.sendCleanupToWorker(
|
|
380
|
+
this.sendCleanupToWorker(workerId, reported.taskId);
|
|
301
381
|
actions.push({ taskId: reported.taskId, action: 'cleanup_unknown' });
|
|
302
382
|
continue;
|
|
303
383
|
}
|
|
304
|
-
// Task exists but is assigned to a different
|
|
305
|
-
const action = this.reconcileReportedTask(
|
|
384
|
+
// Task exists but is assigned to a different worker or already processed
|
|
385
|
+
const action = this.reconcileReportedTask(worker, task, reported);
|
|
306
386
|
actions.push({ taskId: task.id, action });
|
|
307
387
|
}
|
|
308
|
-
this.logger.log(`Reconnect reconciliation for
|
|
388
|
+
this.logger.log(`Reconnect reconciliation for worker ${workerId}: ${actions.length} tasks processed`);
|
|
309
389
|
return actions;
|
|
310
390
|
}
|
|
311
391
|
// ---------------------------------------------------------------------------
|
|
312
392
|
// Private: reconcile a single reported task (branches a-e)
|
|
313
393
|
// ---------------------------------------------------------------------------
|
|
314
|
-
reconcileReportedTask(
|
|
394
|
+
reconcileReportedTask(worker, task, reported) {
|
|
315
395
|
const { taskId, localStatus, currentStage, branch, mrUrl, errorMessage } = reported;
|
|
316
396
|
switch (task.status) {
|
|
317
397
|
// Branch (a): SUSPENDED + still_running → RUNNING (if admission ok)
|
|
318
398
|
// Branch (b): SUSPENDED + completed_locally → COMPLETED
|
|
319
399
|
case protocol_1.TaskStatus.SUSPENDED: {
|
|
320
|
-
if (localStatus ===
|
|
400
|
+
if (localStatus === protocol_1.LocalStatus.STILL_RUNNING) {
|
|
321
401
|
const activeCount = this.taskRepo.countActive();
|
|
322
402
|
if (activeCount < protocol_1.MAX_CONCURRENT_TASKS) {
|
|
323
403
|
const extra = {};
|
|
@@ -330,7 +410,8 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
330
410
|
msgId: crypto.randomUUID(),
|
|
331
411
|
taskId,
|
|
332
412
|
};
|
|
333
|
-
this.workerConnectionManager.send(
|
|
413
|
+
this.workerConnectionManager.send(worker.id, resumeFrame);
|
|
414
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.RUNNING, task.status, task.workerId, task.projectKey);
|
|
334
415
|
this.logger.log(`Task #${taskId}: SUSPENDED → RUNNING (reconnect, admission ok)`);
|
|
335
416
|
return 'resumed';
|
|
336
417
|
}
|
|
@@ -343,7 +424,7 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
343
424
|
});
|
|
344
425
|
return 'admission_blocked';
|
|
345
426
|
}
|
|
346
|
-
if (localStatus ===
|
|
427
|
+
if (localStatus === protocol_1.LocalStatus.COMPLETED_LOCALLY) {
|
|
347
428
|
const extra = {
|
|
348
429
|
completedAt: new Date().toISOString(),
|
|
349
430
|
};
|
|
@@ -352,18 +433,20 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
352
433
|
if (mrUrl)
|
|
353
434
|
extra['mrUrl'] = mrUrl;
|
|
354
435
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.COMPLETED, task.revision, extra);
|
|
355
|
-
if (task.
|
|
356
|
-
this.scheduleWorkspaceCleanup(taskId, task.
|
|
436
|
+
if (task.workerId)
|
|
437
|
+
this.scheduleWorkspaceCleanup(taskId, task.workerId);
|
|
438
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.COMPLETED, task.status, task.workerId, task.projectKey);
|
|
357
439
|
this.logger.log(`Task #${taskId}: SUSPENDED → COMPLETED (completed during disconnect)`);
|
|
358
440
|
return 'completed';
|
|
359
441
|
}
|
|
360
|
-
if (localStatus ===
|
|
442
|
+
if (localStatus === protocol_1.LocalStatus.FAILED_LOCALLY) {
|
|
361
443
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
362
444
|
errorMessage: errorMessage ?? 'Task failed locally during disconnect',
|
|
363
445
|
completedAt: new Date().toISOString(),
|
|
364
446
|
});
|
|
365
|
-
if (task.
|
|
366
|
-
this.scheduleWorkspaceCleanup(taskId, task.
|
|
447
|
+
if (task.workerId)
|
|
448
|
+
this.scheduleWorkspaceCleanup(taskId, task.workerId);
|
|
449
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
367
450
|
this.logger.log(`Task #${taskId}: SUSPENDED → FAILED (failed during disconnect)`);
|
|
368
451
|
return 'failed';
|
|
369
452
|
}
|
|
@@ -372,12 +455,12 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
372
455
|
// Branch (c): FAILED + still_running → notify Worker cleanup
|
|
373
456
|
// Branch (d): FAILED + completed_locally → restore to COMPLETED
|
|
374
457
|
case protocol_1.TaskStatus.FAILED: {
|
|
375
|
-
if (localStatus ===
|
|
458
|
+
if (localStatus === protocol_1.LocalStatus.STILL_RUNNING) {
|
|
376
459
|
this.logger.log(`Task #${taskId}: FAILED but still running on Worker, sending cancel`);
|
|
377
|
-
this.sendCancelToWorker(
|
|
460
|
+
this.sendCancelToWorker(worker.id, taskId);
|
|
378
461
|
return 'send_cancel';
|
|
379
462
|
}
|
|
380
|
-
if (localStatus ===
|
|
463
|
+
if (localStatus === protocol_1.LocalStatus.COMPLETED_LOCALLY) {
|
|
381
464
|
const extra = {
|
|
382
465
|
completedAt: new Date().toISOString(),
|
|
383
466
|
errorMessage: null,
|
|
@@ -387,8 +470,9 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
387
470
|
if (mrUrl)
|
|
388
471
|
extra['mrUrl'] = mrUrl;
|
|
389
472
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.COMPLETED, task.revision, extra);
|
|
390
|
-
if (task.
|
|
391
|
-
this.scheduleWorkspaceCleanup(taskId, task.
|
|
473
|
+
if (task.workerId)
|
|
474
|
+
this.scheduleWorkspaceCleanup(taskId, task.workerId);
|
|
475
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.COMPLETED, task.status, task.workerId, task.projectKey);
|
|
392
476
|
this.auditLogRepo.create({
|
|
393
477
|
action: 'reconcile_restore_completed',
|
|
394
478
|
resource: `task:${taskId}`,
|
|
@@ -401,12 +485,12 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
401
485
|
}
|
|
402
486
|
// Branch (e): CANCELLED → notify Worker to stop
|
|
403
487
|
case protocol_1.TaskStatus.CANCELLED: {
|
|
404
|
-
if (localStatus ===
|
|
405
|
-
localStatus ===
|
|
488
|
+
if (localStatus === protocol_1.LocalStatus.STILL_RUNNING ||
|
|
489
|
+
localStatus === protocol_1.LocalStatus.COMPLETED_LOCALLY) {
|
|
406
490
|
// Keep CANCELLED (user intent priority), notify Worker to stop
|
|
407
491
|
this.logger.log(`Task #${taskId}: CANCELLED, notifying Worker to stop (localStatus=${localStatus})`);
|
|
408
|
-
this.sendCancelToWorker(
|
|
409
|
-
if (localStatus ===
|
|
492
|
+
this.sendCancelToWorker(worker.id, taskId);
|
|
493
|
+
if (localStatus === protocol_1.LocalStatus.COMPLETED_LOCALLY) {
|
|
410
494
|
this.auditLogRepo.create({
|
|
411
495
|
action: 'reconcile_cancelled_but_completed',
|
|
412
496
|
resource: `task:${taskId}`,
|
|
@@ -419,13 +503,13 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
419
503
|
}
|
|
420
504
|
// RUNNING: Worker confirms still running or reports completion/failure
|
|
421
505
|
case protocol_1.TaskStatus.RUNNING: {
|
|
422
|
-
if (localStatus ===
|
|
506
|
+
if (localStatus === protocol_1.LocalStatus.STILL_RUNNING) {
|
|
423
507
|
if (currentStage && currentStage !== task.currentStage) {
|
|
424
508
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.RUNNING, task.revision, { currentStage });
|
|
425
509
|
}
|
|
426
510
|
return 'no_op';
|
|
427
511
|
}
|
|
428
|
-
if (localStatus ===
|
|
512
|
+
if (localStatus === protocol_1.LocalStatus.COMPLETED_LOCALLY) {
|
|
429
513
|
const extra = {
|
|
430
514
|
completedAt: new Date().toISOString(),
|
|
431
515
|
};
|
|
@@ -434,18 +518,20 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
434
518
|
if (mrUrl)
|
|
435
519
|
extra['mrUrl'] = mrUrl;
|
|
436
520
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.COMPLETED, task.revision, extra);
|
|
437
|
-
if (task.
|
|
438
|
-
this.scheduleWorkspaceCleanup(taskId, task.
|
|
521
|
+
if (task.workerId)
|
|
522
|
+
this.scheduleWorkspaceCleanup(taskId, task.workerId);
|
|
523
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.COMPLETED, task.status, task.workerId, task.projectKey);
|
|
439
524
|
this.logger.log(`Task #${taskId}: RUNNING → COMPLETED (completed during disconnect)`);
|
|
440
525
|
return 'completed';
|
|
441
526
|
}
|
|
442
|
-
if (localStatus ===
|
|
527
|
+
if (localStatus === protocol_1.LocalStatus.FAILED_LOCALLY) {
|
|
443
528
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.FAILED, task.revision, {
|
|
444
529
|
errorMessage: errorMessage ?? 'Task failed locally during disconnect',
|
|
445
530
|
completedAt: new Date().toISOString(),
|
|
446
531
|
});
|
|
447
|
-
if (task.
|
|
448
|
-
this.scheduleWorkspaceCleanup(taskId, task.
|
|
532
|
+
if (task.workerId)
|
|
533
|
+
this.scheduleWorkspaceCleanup(taskId, task.workerId);
|
|
534
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.FAILED, task.status, task.workerId, task.projectKey);
|
|
449
535
|
this.logger.log(`Task #${taskId}: RUNNING → FAILED (failed during disconnect)`);
|
|
450
536
|
return 'failed';
|
|
451
537
|
}
|
|
@@ -453,14 +539,15 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
453
539
|
}
|
|
454
540
|
// ASSIGNED: Worker may have started executing before we recorded RUNNING
|
|
455
541
|
case protocol_1.TaskStatus.ASSIGNED: {
|
|
456
|
-
if (localStatus ===
|
|
542
|
+
if (localStatus === protocol_1.LocalStatus.STILL_RUNNING) {
|
|
457
543
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.RUNNING, task.revision, {
|
|
458
544
|
startedAt: new Date().toISOString(),
|
|
459
545
|
});
|
|
546
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.RUNNING, task.status, task.workerId, task.projectKey);
|
|
460
547
|
this.logger.log(`Task #${taskId}: ASSIGNED → RUNNING (Worker reports still_running)`);
|
|
461
548
|
return 'promoted_to_running';
|
|
462
549
|
}
|
|
463
|
-
if (localStatus ===
|
|
550
|
+
if (localStatus === protocol_1.LocalStatus.COMPLETED_LOCALLY) {
|
|
464
551
|
const extra = {
|
|
465
552
|
completedAt: new Date().toISOString(),
|
|
466
553
|
startedAt: task.startedAt ?? new Date().toISOString(),
|
|
@@ -470,8 +557,9 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
470
557
|
if (mrUrl)
|
|
471
558
|
extra['mrUrl'] = mrUrl;
|
|
472
559
|
this.updateTaskStatusSafe(taskId, protocol_1.TaskStatus.COMPLETED, task.revision, extra);
|
|
473
|
-
if (task.
|
|
474
|
-
this.scheduleWorkspaceCleanup(taskId, task.
|
|
560
|
+
if (task.workerId)
|
|
561
|
+
this.scheduleWorkspaceCleanup(taskId, task.workerId);
|
|
562
|
+
this.emitTaskStatusChanged(taskId, protocol_1.TaskStatus.COMPLETED, task.status, task.workerId, task.projectKey);
|
|
475
563
|
this.logger.log(`Task #${taskId}: ASSIGNED → COMPLETED (completed locally)`);
|
|
476
564
|
return 'completed';
|
|
477
565
|
}
|
|
@@ -492,35 +580,23 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
492
580
|
* Best-effort for reconciliation — continues processing other tasks on failure.
|
|
493
581
|
*/
|
|
494
582
|
updateTaskStatusSafe(taskId, status, initialRevision, extra) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
if (success)
|
|
499
|
-
return true;
|
|
500
|
-
const freshTask = this.taskRepo.findById(taskId);
|
|
501
|
-
if (!freshTask) {
|
|
502
|
-
this.logger.error(`Task #${taskId} disappeared during CAS retry (reconciliation)`);
|
|
503
|
-
return false;
|
|
504
|
-
}
|
|
505
|
-
// Already at target status — success
|
|
506
|
-
if (freshTask.status === status)
|
|
507
|
-
return true;
|
|
508
|
-
revision = freshTask.revision;
|
|
583
|
+
const { success, task } = this.taskRepo.updateStatusWithCasRetry(taskId, status, initialRevision, extra);
|
|
584
|
+
if (!success) {
|
|
585
|
+
this.logger.error(`CAS retry exhausted for task #${taskId} → ${status} during reconciliation`);
|
|
509
586
|
}
|
|
510
|
-
|
|
511
|
-
return false;
|
|
587
|
+
return success;
|
|
512
588
|
}
|
|
513
589
|
/** Send cancel frame to a Worker for a specific task. */
|
|
514
|
-
sendCancelToWorker(
|
|
590
|
+
sendCancelToWorker(workerId, taskId) {
|
|
515
591
|
const frame = {
|
|
516
592
|
type: 'cancel',
|
|
517
593
|
msgId: crypto.randomUUID(),
|
|
518
594
|
taskId,
|
|
519
595
|
};
|
|
520
|
-
this.workerConnectionManager.send(
|
|
596
|
+
this.workerConnectionManager.send(workerId, frame);
|
|
521
597
|
}
|
|
522
598
|
/** Send cleanup instruction to Worker for a specific task. */
|
|
523
|
-
sendCleanupToWorker(
|
|
599
|
+
sendCleanupToWorker(workerId, taskId) {
|
|
524
600
|
const workspace = this.workspaceRepo.findByTaskId(taskId);
|
|
525
601
|
const frame = {
|
|
526
602
|
type: 'cleanup_workspace',
|
|
@@ -528,20 +604,32 @@ let Reconciler = Reconciler_1 = class Reconciler {
|
|
|
528
604
|
taskId,
|
|
529
605
|
workspacePath: workspace?.path ?? '',
|
|
530
606
|
};
|
|
531
|
-
this.workerConnectionManager.send(
|
|
607
|
+
this.workerConnectionManager.send(workerId, frame);
|
|
608
|
+
}
|
|
609
|
+
/** Emit a TASK_STATUS_CHANGED domain event. */
|
|
610
|
+
emitTaskStatusChanged(taskId, status, previousStatus, workerId, projectKey) {
|
|
611
|
+
this.eventEmitter.emit(event_types_1.DomainEvents.TASK_STATUS_CHANGED, {
|
|
612
|
+
taskId,
|
|
613
|
+
status,
|
|
614
|
+
previousStatus,
|
|
615
|
+
workerId,
|
|
616
|
+
projectKey,
|
|
617
|
+
});
|
|
532
618
|
}
|
|
533
|
-
/** Check if a
|
|
534
|
-
|
|
535
|
-
return !
|
|
619
|
+
/** Check if a worker is unavailable (missing, offline, or decommissioned). */
|
|
620
|
+
isWorkerUnavailable(worker) {
|
|
621
|
+
return !worker || worker.status === protocol_1.WorkerStatus.OFFLINE || worker.status === protocol_1.WorkerStatus.DECOMMISSIONED;
|
|
536
622
|
}
|
|
537
623
|
/** Schedule workspace cleanup for a task that reached a terminal state. */
|
|
538
|
-
scheduleWorkspaceCleanup(taskId,
|
|
624
|
+
scheduleWorkspaceCleanup(taskId, workerId) {
|
|
539
625
|
const workspace = this.workspaceRepo.findByTaskId(taskId);
|
|
540
626
|
if (workspace) {
|
|
541
627
|
this.cleanupService
|
|
542
|
-
.scheduleCleanup(taskId,
|
|
628
|
+
.scheduleCleanup(taskId, workerId, workspace.path)
|
|
543
629
|
.catch((err) => {
|
|
544
|
-
this.logger.error(`Failed to schedule cleanup for task #${taskId}: ${err
|
|
630
|
+
this.logger.error(`Failed to schedule cleanup for task #${taskId}: ${(0, protocol_1.getErrorMessage)(err)}. Marking workspace for cleanup and adding to retry set.`);
|
|
631
|
+
this.workspaceRepo.markForCleanup(taskId);
|
|
632
|
+
this.failedCleanups.set(`${taskId}:${workerId}`, { taskId, workerId });
|
|
545
633
|
});
|
|
546
634
|
}
|
|
547
635
|
}
|
|
@@ -550,11 +638,12 @@ exports.Reconciler = Reconciler;
|
|
|
550
638
|
exports.Reconciler = Reconciler = Reconciler_1 = __decorate([
|
|
551
639
|
(0, common_1.Injectable)(),
|
|
552
640
|
__metadata("design:paramtypes", [task_repository_1.TaskRepository,
|
|
553
|
-
|
|
641
|
+
worker_repository_1.WorkerRepository,
|
|
554
642
|
audit_log_repository_1.AuditLogRepository,
|
|
555
643
|
workspace_repository_1.WorkspaceRepository,
|
|
556
644
|
scheduler_service_1.SchedulerService,
|
|
557
645
|
cleanup_service_1.CleanupService,
|
|
558
|
-
worker_connection_manager_1.WorkerConnectionManager
|
|
646
|
+
worker_connection_manager_1.WorkerConnectionManager,
|
|
647
|
+
event_emitter_1.EventEmitter2])
|
|
559
648
|
], Reconciler);
|
|
560
649
|
//# sourceMappingURL=reconciler.js.map
|