devchain-cli 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drizzle/0066_provider_efforts_and_overrides.sql +29 -0
- package/dist/drizzle/meta/0066_snapshot.json +5803 -0
- package/dist/drizzle/meta/_journal.json +7 -0
- package/dist/node_modules/@devchain/codebase-overview/tsconfig.tsbuildinfo +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +55 -4
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts.map +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js +12 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js.map +1 -1
- package/dist/node_modules/@devchain/shared/tsconfig.tsbuildinfo +1 -1
- package/dist/server/modules/agent-message-delivery/agent-message-delivery.service.js +6 -1
- package/dist/server/modules/agent-message-delivery/agent-message-delivery.service.js.map +1 -1
- package/dist/server/modules/agent-message-delivery/dtos/delivery.types.d.ts +2 -0
- package/dist/server/modules/agents/controllers/agents.controller.d.ts +3 -0
- package/dist/server/modules/agents/controllers/agents.controller.js +6 -0
- package/dist/server/modules/agents/controllers/agents.controller.js.map +1 -1
- package/dist/server/modules/cloud-tunnel/cloud-tunnel.module.js +4 -0
- package/dist/server/modules/cloud-tunnel/cloud-tunnel.module.js.map +1 -1
- package/dist/server/modules/cloud-tunnel/services/mobile-chat-rpc.service.d.ts +6 -1
- package/dist/server/modules/cloud-tunnel/services/mobile-chat-rpc.service.js +18 -2
- package/dist/server/modules/cloud-tunnel/services/mobile-chat-rpc.service.js.map +1 -1
- package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.d.ts +7 -1
- package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.js +63 -2
- package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.js.map +1 -1
- package/dist/server/modules/events/catalog/claude.hooks.session.started.d.ts +2 -2
- package/dist/server/modules/events/catalog/index.d.ts +2 -2
- package/dist/server/modules/hooks/dtos/hook-event.dto.d.ts +16 -16
- package/dist/server/modules/orchestrator/docker/docker.module.js +2 -1
- package/dist/server/modules/orchestrator/docker/docker.module.js.map +1 -1
- package/dist/server/modules/orchestrator/docker/services/docker.service.d.ts +3 -9
- package/dist/server/modules/orchestrator/docker/services/docker.service.js +19 -170
- package/dist/server/modules/orchestrator/docker/services/docker.service.js.map +1 -1
- package/dist/server/modules/orchestrator/docker/services/worktree-mount-discovery.service.d.ts +20 -0
- package/dist/server/modules/orchestrator/docker/services/worktree-mount-discovery.service.js +191 -0
- package/dist/server/modules/orchestrator/docker/services/worktree-mount-discovery.service.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/container-runtime.d.ts +17 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/container-runtime.js +58 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/container-runtime.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/process-runtime.d.ts +38 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/process-runtime.js +295 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/process-runtime.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/worktree-runtime.d.ts +15 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/worktree-runtime.js +3 -0
- package/dist/server/modules/orchestrator/worktrees/runtime/worktree-runtime.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/services/worktrees.service.d.ts +12 -17
- package/dist/server/modules/orchestrator/worktrees/services/worktrees.service.js +83 -304
- package/dist/server/modules/orchestrator/worktrees/services/worktrees.service.js.map +1 -1
- package/dist/server/modules/orchestrator/worktrees/worktrees.module.js +4 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.module.js.map +1 -1
- package/dist/server/modules/profiles/controllers/profiles.controller.js +2 -0
- package/dist/server/modules/profiles/controllers/profiles.controller.js.map +1 -1
- package/dist/server/modules/profiles/controllers/provider-configs.controller.js +6 -0
- package/dist/server/modules/profiles/controllers/provider-configs.controller.js.map +1 -1
- package/dist/server/modules/profiles/dto.d.ts +24 -6
- package/dist/server/modules/profiles/dto.js +14 -0
- package/dist/server/modules/profiles/dto.js.map +1 -1
- package/dist/server/modules/projects/controllers/projects.controller.d.ts +60 -35
- package/dist/server/modules/projects/controllers/projects.controller.js +90 -8
- package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
- package/dist/server/modules/projects/dtos/export.dto.d.ts +7 -0
- package/dist/server/modules/projects/dtos/export.dto.js +1 -0
- package/dist/server/modules/projects/dtos/export.dto.js.map +1 -1
- package/dist/server/modules/projects/dtos/setup-preview.dto.d.ts +28 -0
- package/dist/server/modules/projects/dtos/setup-preview.dto.js +3 -0
- package/dist/server/modules/projects/dtos/setup-preview.dto.js.map +1 -0
- package/dist/server/modules/projects/helpers/profile-mapping.helpers.d.ts +26 -2
- package/dist/server/modules/projects/helpers/profile-mapping.helpers.js +140 -4
- package/dist/server/modules/projects/helpers/profile-mapping.helpers.js.map +1 -1
- package/dist/server/modules/projects/helpers/project-export.d.ts +26 -17
- package/dist/server/modules/projects/helpers/project-export.js +36 -323
- package/dist/server/modules/projects/helpers/project-export.js.map +1 -1
- package/dist/server/modules/projects/helpers/project-import.d.ts +13 -16
- package/dist/server/modules/projects/helpers/project-import.js +56 -354
- package/dist/server/modules/projects/helpers/project-import.js.map +1 -1
- package/dist/server/modules/projects/helpers/project-presets.helpers.d.ts +5 -0
- package/dist/server/modules/projects/helpers/project-presets.helpers.js +32 -14
- package/dist/server/modules/projects/helpers/project-presets.helpers.js.map +1 -1
- package/dist/server/modules/projects/helpers/team-overrides.helpers.d.ts +26 -0
- package/dist/server/modules/projects/helpers/team-overrides.helpers.js +53 -0
- package/dist/server/modules/projects/helpers/team-overrides.helpers.js.map +1 -0
- package/dist/server/modules/projects/helpers/template-loader.d.ts +16 -4
- package/dist/server/modules/projects/helpers/template-loader.js +93 -308
- package/dist/server/modules/projects/helpers/template-loader.js.map +1 -1
- package/dist/server/modules/projects/projects.module.js +2 -0
- package/dist/server/modules/projects/projects.module.js.map +1 -1
- package/dist/server/modules/projects/services/projects.service.d.ts +41 -21
- package/dist/server/modules/projects/services/projects.service.js +69 -7
- package/dist/server/modules/projects/services/projects.service.js.map +1 -1
- package/dist/server/modules/projects/template-codec/codec-registry.d.ts +3 -0
- package/dist/server/modules/projects/template-codec/codec-registry.js +33 -0
- package/dist/server/modules/projects/template-codec/codec-registry.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/agents.codec.d.ts +40 -0
- package/dist/server/modules/projects/template-codec/codecs/agents.codec.js +96 -0
- package/dist/server/modules/projects/template-codec/codecs/agents.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/presets.codec.d.ts +16 -0
- package/dist/server/modules/projects/template-codec/codecs/presets.codec.js +34 -0
- package/dist/server/modules/projects/template-codec/codecs/presets.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/profiles.codec.d.ts +71 -0
- package/dist/server/modules/projects/template-codec/codecs/profiles.codec.js +152 -0
- package/dist/server/modules/projects/template-codec/codecs/profiles.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/project-settings.codec.d.ts +42 -0
- package/dist/server/modules/projects/template-codec/codecs/project-settings.codec.js +68 -0
- package/dist/server/modules/projects/template-codec/codecs/project-settings.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/prompts.codec.d.ts +31 -0
- package/dist/server/modules/projects/template-codec/codecs/prompts.codec.js +53 -0
- package/dist/server/modules/projects/template-codec/codecs/prompts.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-efforts.codec.d.ts +23 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-efforts.codec.js +73 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-efforts.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-models.codec.d.ts +23 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-models.codec.js +73 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-models.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-settings.codec.d.ts +36 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-settings.codec.js +138 -0
- package/dist/server/modules/projects/template-codec/codecs/provider-settings.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/scheduled-epics.codec.d.ts +46 -0
- package/dist/server/modules/projects/template-codec/codecs/scheduled-epics.codec.js +120 -0
- package/dist/server/modules/projects/template-codec/codecs/scheduled-epics.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/statuses.codec.d.ts +32 -0
- package/dist/server/modules/projects/template-codec/codecs/statuses.codec.js +101 -0
- package/dist/server/modules/projects/template-codec/codecs/statuses.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/subscribers.codec.d.ts +65 -0
- package/dist/server/modules/projects/template-codec/codecs/subscribers.codec.js +47 -0
- package/dist/server/modules/projects/template-codec/codecs/subscribers.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/teams.codec.d.ts +83 -0
- package/dist/server/modules/projects/template-codec/codecs/teams.codec.js +297 -0
- package/dist/server/modules/projects/template-codec/codecs/teams.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/codecs/watchers.codec.d.ts +62 -0
- package/dist/server/modules/projects/template-codec/codecs/watchers.codec.js +78 -0
- package/dist/server/modules/projects/template-codec/codecs/watchers.codec.js.map +1 -0
- package/dist/server/modules/projects/template-codec/import-context.d.ts +38 -0
- package/dist/server/modules/projects/template-codec/import-context.js +49 -0
- package/dist/server/modules/projects/template-codec/import-context.js.map +1 -0
- package/dist/server/modules/projects/template-codec/template-pipeline.d.ts +17 -0
- package/dist/server/modules/projects/template-codec/template-pipeline.js +159 -0
- package/dist/server/modules/projects/template-codec/template-pipeline.js.map +1 -0
- package/dist/server/modules/projects/template-codec/template-section-codec.d.ts +93 -0
- package/dist/server/modules/projects/template-codec/template-section-codec.js +3 -0
- package/dist/server/modules/projects/template-codec/template-section-codec.js.map +1 -0
- package/dist/server/modules/providers/adapters/capabilities/effort.capability.d.ts +8 -0
- package/dist/server/modules/providers/adapters/capabilities/effort.capability.js +3 -0
- package/dist/server/modules/providers/adapters/capabilities/effort.capability.js.map +1 -0
- package/dist/server/modules/providers/adapters/capabilities/index.d.ts +2 -2
- package/dist/server/modules/providers/adapters/capabilities/index.js +2 -1
- package/dist/server/modules/providers/adapters/capabilities/index.js.map +1 -1
- package/dist/server/modules/providers/adapters/capabilities/type-guards.d.ts +3 -0
- package/dist/server/modules/providers/adapters/capabilities/type-guards.js +4 -0
- package/dist/server/modules/providers/adapters/capabilities/type-guards.js.map +1 -1
- package/dist/server/modules/providers/adapters/claude.adapter.d.ts +7 -2
- package/dist/server/modules/providers/adapters/claude.adapter.js +5 -0
- package/dist/server/modules/providers/adapters/claude.adapter.js.map +1 -1
- package/dist/server/modules/providers/adapters/codex.adapter.d.ts +9 -2
- package/dist/server/modules/providers/adapters/codex.adapter.js +26 -0
- package/dist/server/modules/providers/adapters/codex.adapter.js.map +1 -1
- package/dist/server/modules/providers/adapters/copilot.adapter.d.ts +7 -2
- package/dist/server/modules/providers/adapters/copilot.adapter.js +7 -0
- package/dist/server/modules/providers/adapters/copilot.adapter.js.map +1 -1
- package/dist/server/modules/providers/adapters/opencode.adapter.d.ts +8 -1
- package/dist/server/modules/providers/adapters/opencode.adapter.js +54 -0
- package/dist/server/modules/providers/adapters/opencode.adapter.js.map +1 -1
- package/dist/server/modules/providers/controllers/provider-efforts.controller.d.ts +20 -0
- package/dist/server/modules/providers/controllers/provider-efforts.controller.js +128 -0
- package/dist/server/modules/providers/controllers/provider-efforts.controller.js.map +1 -0
- package/dist/server/modules/providers/controllers/providers.controller.d.ts +3 -1
- package/dist/server/modules/providers/controllers/providers.controller.js +11 -2
- package/dist/server/modules/providers/controllers/providers.controller.js.map +1 -1
- package/dist/server/modules/providers/providers.module.js +4 -1
- package/dist/server/modules/providers/providers.module.js.map +1 -1
- package/dist/server/modules/providers/services/provider-effort-seeding.module.d.ts +2 -0
- package/dist/server/modules/providers/services/provider-effort-seeding.module.js +24 -0
- package/dist/server/modules/providers/services/provider-effort-seeding.module.js.map +1 -0
- package/dist/server/modules/providers/services/provider-effort-seeding.service.d.ts +19 -0
- package/dist/server/modules/providers/services/provider-effort-seeding.service.js +64 -0
- package/dist/server/modules/providers/services/provider-effort-seeding.service.js.map +1 -0
- package/dist/server/modules/providers/services/provider-project-sync.service.js +34 -3
- package/dist/server/modules/providers/services/provider-project-sync.service.js.map +1 -1
- package/dist/server/modules/providers/services/provider-state-manager.service.d.ts +4 -1
- package/dist/server/modules/providers/services/provider-state-manager.service.js +14 -2
- package/dist/server/modules/providers/services/provider-state-manager.service.js.map +1 -1
- package/dist/server/modules/registry/controllers/templates.controller.d.ts +10 -1
- package/dist/server/modules/seeders/seeders/0010_seed_provider_effort_defaults.d.ts +3 -0
- package/dist/server/modules/seeders/seeders/0010_seed_provider_effort_defaults.js +21 -0
- package/dist/server/modules/seeders/seeders/0010_seed_provider_effort_defaults.js.map +1 -0
- package/dist/server/modules/seeders/seeders.module.js +2 -1
- package/dist/server/modules/seeders/seeders.module.js.map +1 -1
- package/dist/server/modules/seeders/services/data-seeder.service.d.ts +3 -1
- package/dist/server/modules/seeders/services/data-seeder.service.js +10 -4
- package/dist/server/modules/seeders/services/data-seeder.service.js.map +1 -1
- package/dist/server/modules/seeders/types/seeder.types.d.ts +2 -0
- package/dist/server/modules/session-reader/adapters/codex-session-reader.adapter.d.ts +3 -2
- package/dist/server/modules/session-reader/adapters/codex-session-reader.adapter.js +22 -14
- package/dist/server/modules/session-reader/adapters/codex-session-reader.adapter.js.map +1 -1
- package/dist/server/modules/session-reader/adapters/session-reader-adapter.interface.d.ts +7 -0
- package/dist/server/modules/session-reader/data/pricing.json +40 -40
- package/dist/server/modules/session-reader/services/transcript-persistence.listener.d.ts +1 -0
- package/dist/server/modules/session-reader/services/transcript-persistence.listener.js +41 -33
- package/dist/server/modules/session-reader/services/transcript-persistence.listener.js.map +1 -1
- package/dist/server/modules/sessions/services/message-enqueue.service.d.ts +1 -0
- package/dist/server/modules/sessions/services/message-enqueue.service.js +1 -0
- package/dist/server/modules/sessions/services/message-enqueue.service.js.map +1 -1
- package/dist/server/modules/sessions/services/message-log.service.d.ts +3 -0
- package/dist/server/modules/sessions/services/message-log.service.js +35 -3
- package/dist/server/modules/sessions/services/message-log.service.js.map +1 -1
- package/dist/server/modules/sessions/services/message-pool.types.d.ts +4 -0
- package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.d.ts +1 -0
- package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.js +6 -0
- package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.js.map +1 -1
- package/dist/server/modules/sessions/services/session-runtime/__test-utils__/pipeline-harness.d.ts +7 -0
- package/dist/server/modules/sessions/services/session-runtime/__test-utils__/pipeline-harness.js +7 -0
- package/dist/server/modules/sessions/services/session-runtime/__test-utils__/pipeline-harness.js.map +1 -1
- package/dist/server/modules/sessions/services/session-runtime/session-launch-pipeline.service.js +9 -1
- package/dist/server/modules/sessions/services/session-runtime/session-launch-pipeline.service.js.map +1 -1
- package/dist/server/modules/sessions/services/session-runtime/session-restore-pipeline.service.js +14 -1
- package/dist/server/modules/sessions/services/session-runtime/session-restore-pipeline.service.js.map +1 -1
- package/dist/server/modules/sessions/services/sessions-message-log-read.facade.d.ts +16 -0
- package/dist/server/modules/sessions/services/sessions-message-log-read.facade.js +40 -0
- package/dist/server/modules/sessions/services/sessions-message-log-read.facade.js.map +1 -0
- package/dist/server/modules/sessions/services/sessions-message-pool.service.js +21 -4
- package/dist/server/modules/sessions/services/sessions-message-pool.service.js.map +1 -1
- package/dist/server/modules/sessions/services/sessions.service.js +4 -0
- package/dist/server/modules/sessions/services/sessions.service.js.map +1 -1
- package/dist/server/modules/sessions/sessions-message-log-read.module.d.ts +2 -0
- package/dist/server/modules/sessions/sessions-message-log-read.module.js +23 -0
- package/dist/server/modules/sessions/sessions-message-log-read.module.js.map +1 -0
- package/dist/server/modules/sessions/utils/profile-options.d.ts +1 -0
- package/dist/server/modules/sessions/utils/profile-options.js +18 -0
- package/dist/server/modules/sessions/utils/profile-options.js.map +1 -1
- package/dist/server/modules/settings/dtos/settings.dto.d.ts +15 -0
- package/dist/server/modules/settings/dtos/settings.dto.js +1 -0
- package/dist/server/modules/settings/dtos/settings.dto.js.map +1 -1
- package/dist/server/modules/storage/db/schema.d.ts +176 -0
- package/dist/server/modules/storage/db/schema.js +18 -2
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +13 -62
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/delegates/agent.delegate.js +3 -0
- package/dist/server/modules/storage/local/delegates/agent.delegate.js.map +1 -1
- package/dist/server/modules/storage/local/delegates/profile-provider-config.delegate.d.ts +2 -0
- package/dist/server/modules/storage/local/delegates/profile-provider-config.delegate.js +24 -0
- package/dist/server/modules/storage/local/delegates/profile-provider-config.delegate.js.map +1 -1
- package/dist/server/modules/storage/local/delegates/project.delegate.d.ts +3 -2
- package/dist/server/modules/storage/local/delegates/project.delegate.js +25 -198
- package/dist/server/modules/storage/local/delegates/project.delegate.js.map +1 -1
- package/dist/server/modules/storage/local/delegates/provider-effort.delegate.d.ts +15 -0
- package/dist/server/modules/storage/local/delegates/provider-effort.delegate.js +200 -0
- package/dist/server/modules/storage/local/delegates/provider-effort.delegate.js.map +1 -0
- package/dist/server/modules/storage/local/local-storage.service.d.ts +12 -2
- package/dist/server/modules/storage/local/local-storage.service.js +22 -2
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +18 -1
- package/dist/server/modules/teams/services/teams.service.d.ts +0 -5
- package/dist/server/modules/teams/services/teams.service.js +22 -131
- package/dist/server/modules/teams/services/teams.service.js.map +1 -1
- package/dist/server/modules/teams/services/teams.validators.d.ts +14 -0
- package/dist/server/modules/teams/services/teams.validators.js +94 -0
- package/dist/server/modules/teams/services/teams.validators.js.map +1 -0
- package/dist/server/modules/terminal/gateways/terminal.gateway.d.ts +1 -0
- package/dist/server/modules/terminal/gateways/terminal.gateway.js +39 -10
- package/dist/server/modules/terminal/gateways/terminal.gateway.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.d.ts +10 -0
- package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.js +73 -0
- package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.js.map +1 -0
- package/dist/server/modules/terminal/services/terminal-registry-rehydrator.service.js +1 -0
- package/dist/server/modules/terminal/services/terminal-registry-rehydrator.service.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-session/terminal-session.d.ts +2 -0
- package/dist/server/modules/terminal/services/terminal-session/terminal-session.js +15 -0
- package/dist/server/modules/terminal/services/terminal-session/terminal-session.js.map +1 -1
- package/dist/server/modules/terminal/terminal-key-input.module.d.ts +2 -0
- package/dist/server/modules/terminal/terminal-key-input.module.js +23 -0
- package/dist/server/modules/terminal/terminal-key-input.module.js.map +1 -0
- package/dist/server/modules/watchers/services/watcher-runner.service.d.ts +2 -16
- package/dist/server/modules/watchers/services/watcher-runner.service.js +11 -125
- package/dist/server/modules/watchers/services/watcher-runner.service.js.map +1 -1
- package/dist/server/modules/watchers/services/watcher-trigger-state.d.ts +23 -0
- package/dist/server/modules/watchers/services/watcher-trigger-state.js +136 -0
- package/dist/server/modules/watchers/services/watcher-trigger-state.js.map +1 -0
- package/dist/server/templates/3-agents-dev.json +144 -85
- package/dist/server/templates/teams-dev.json +305 -208
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/{ReviewDetailPage-BDisSE9l.js → ReviewDetailPage-Dd40lXMW.js} +1 -1
- package/dist/server/ui/assets/{ReviewsPage-3puoJiOQ.js → ReviewsPage-CBSbsimJ.js} +1 -1
- package/dist/server/ui/assets/index-COvyD_66.css +32 -0
- package/dist/server/ui/assets/index-DtIjl-Lt.js +1113 -0
- package/dist/server/ui/assets/{useReviewSubscription-wTrdkdi0.js → useReviewSubscription-CpDyx3vJ.js} +1 -1
- package/dist/server/ui/index.html +2 -2
- package/dist/templates/3-agents-dev.json +144 -85
- package/dist/templates/teams-dev.json +305 -208
- package/package.json +11 -1
- package/dist/server/ui/assets/index-CzMrWNAV.css +0 -32
- package/dist/server/ui/assets/index-zlQ1ekQ2.js +0 -1103
|
@@ -16,15 +16,15 @@ exports.WorktreesService = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
18
18
|
const crypto_1 = require("crypto");
|
|
19
|
-
const fs_1 = require("fs");
|
|
20
19
|
const logger_1 = require("../../../../common/logging/logger");
|
|
21
20
|
const env_config_1 = require("../../../../common/config/env.config");
|
|
22
21
|
const event_log_service_1 = require("../../../events/services/event-log.service");
|
|
23
22
|
const worktree_dto_1 = require("../dtos/worktree.dto");
|
|
24
23
|
const worktrees_store_1 = require("../worktrees.store");
|
|
25
24
|
const git_worktree_service_1 = require("../../git/services/git-worktree.service");
|
|
26
|
-
const docker_service_1 = require("../../docker/services/docker.service");
|
|
27
25
|
const seed_preparation_service_1 = require("../../docker/services/seed-preparation.service");
|
|
26
|
+
const container_runtime_1 = require("../runtime/container-runtime");
|
|
27
|
+
const process_runtime_1 = require("../runtime/process-runtime");
|
|
28
28
|
const task_merge_events_1 = require("../../sync/events/task-merge.events");
|
|
29
29
|
const worktree_events_1 = require("../events/worktree.events");
|
|
30
30
|
const promises_1 = require("fs/promises");
|
|
@@ -33,33 +33,26 @@ const worktree_validation_1 = require("../worktree-validation");
|
|
|
33
33
|
const storage_interface_1 = require("../../../storage/interfaces/storage.interface");
|
|
34
34
|
const error_types_1 = require("../../../../common/errors/error-types");
|
|
35
35
|
const path_validation_1 = require("../../../../common/validation/path-validation");
|
|
36
|
-
const process_executor_port_1 = require("../../../terminal/services/process-executor/process-executor.port");
|
|
37
36
|
const logger = (0, logger_1.createLogger)('OrchestratorWorktreesService');
|
|
38
37
|
const CONTAINER_HEALTH_TIMEOUT_MS = 60_000;
|
|
39
38
|
const HEALTH_MONITOR_INTERVAL_MS = 15_000;
|
|
40
39
|
const HEALTH_MONITOR_PROBE_TIMEOUT_MS = 1_500;
|
|
41
40
|
const MAX_CONSECUTIVE_HEALTH_FAILURES = 3;
|
|
42
41
|
const OVERVIEW_FETCH_TIMEOUT_MS = 2_500;
|
|
43
|
-
const PROCESS_SHUTDOWN_TIMEOUT_MS = 30_000;
|
|
44
|
-
const PROCESS_KILL_TIMEOUT_MS = 5_000;
|
|
45
|
-
const PROCESS_LOG_FILE_NAME = 'devchain.log';
|
|
46
|
-
const PROCESS_DB_FILE_NAME = 'devchain.db';
|
|
47
|
-
const PROCESS_RUNTIME_PORT_FILE = 'runtime-port.json';
|
|
48
|
-
const PROCESS_HEALTH_POLL_INTERVAL_MS = 1_000;
|
|
49
|
-
const PROCESS_RUNTIME_TIMEOUT_MS = 1_500;
|
|
50
42
|
const WORKTREE_ACTIVITY_EVENT_NAME = 'orchestrator.worktree.activity';
|
|
51
43
|
const WORKTREE_STATUS_VALUES = worktree_dto_1.WorktreeStatusSchema.options;
|
|
52
44
|
let WorktreesService = class WorktreesService {
|
|
53
|
-
constructor(store,
|
|
45
|
+
constructor(store, containerRuntime, processRuntime, gitService, seedPreparationService, eventEmitter, eventLogService, storage) {
|
|
54
46
|
this.store = store;
|
|
55
|
-
this.
|
|
47
|
+
this.containerRuntime = containerRuntime;
|
|
48
|
+
this.processRuntime = processRuntime;
|
|
56
49
|
this.gitService = gitService;
|
|
57
50
|
this.seedPreparationService = seedPreparationService;
|
|
58
51
|
this.eventEmitter = eventEmitter;
|
|
59
52
|
this.eventLogService = eventLogService;
|
|
60
53
|
this.storage = storage;
|
|
61
|
-
this.executor = executor;
|
|
62
54
|
this.consecutiveHealthFailures = new Map();
|
|
55
|
+
this.inFlightOperations = new Map();
|
|
63
56
|
}
|
|
64
57
|
async onModuleInit() {
|
|
65
58
|
this.monitorTimer = setInterval(() => {
|
|
@@ -71,7 +64,7 @@ let WorktreesService = class WorktreesService {
|
|
|
71
64
|
logger.warn({ error }, 'Failed process-runtime orphan detection on startup');
|
|
72
65
|
});
|
|
73
66
|
try {
|
|
74
|
-
this.unsubscribeDockerEvents = await this.
|
|
67
|
+
this.unsubscribeDockerEvents = await this.containerRuntime.subscribeToContainerEvents((event) => {
|
|
75
68
|
this.handleContainerEvent(event).catch((error) => {
|
|
76
69
|
logger.error({ error, event }, 'Failed handling docker container event');
|
|
77
70
|
});
|
|
@@ -166,7 +159,7 @@ let WorktreesService = class WorktreesService {
|
|
|
166
159
|
await (0, promises_1.mkdir)(dataPath, { recursive: true });
|
|
167
160
|
await this.seedPreparationService.prepareSeedData(dataPath);
|
|
168
161
|
if (runtimeType === 'process') {
|
|
169
|
-
const runtime = await this.startProcessRuntime({
|
|
162
|
+
const runtime = await this.processRuntime.startProcessRuntime({
|
|
170
163
|
worktreePath,
|
|
171
164
|
dataPath,
|
|
172
165
|
projectId,
|
|
@@ -192,7 +185,7 @@ let WorktreesService = class WorktreesService {
|
|
|
192
185
|
}));
|
|
193
186
|
}
|
|
194
187
|
else {
|
|
195
|
-
const container = await this.
|
|
188
|
+
const container = await this.containerRuntime.createContainer({
|
|
196
189
|
name: containerName,
|
|
197
190
|
worktreePath,
|
|
198
191
|
dataPath,
|
|
@@ -205,10 +198,10 @@ let WorktreesService = class WorktreesService {
|
|
|
205
198
|
},
|
|
206
199
|
});
|
|
207
200
|
containerId = container.id;
|
|
208
|
-
await this.
|
|
201
|
+
await this.containerRuntime
|
|
209
202
|
.ensureWorktreeOnComposeNetwork(input.name, container.id)
|
|
210
203
|
.catch(() => undefined);
|
|
211
|
-
const healthy = await this.
|
|
204
|
+
const healthy = await this.containerRuntime.waitForHealthy(container.id, CONTAINER_HEALTH_TIMEOUT_MS);
|
|
212
205
|
if (!healthy) {
|
|
213
206
|
throw new Error('Container did not become healthy before timeout');
|
|
214
207
|
}
|
|
@@ -251,10 +244,10 @@ let WorktreesService = class WorktreesService {
|
|
|
251
244
|
errorMessage,
|
|
252
245
|
});
|
|
253
246
|
if (containerId) {
|
|
254
|
-
await this.
|
|
247
|
+
await this.containerRuntime.removeContainer(containerId, true).catch(() => undefined);
|
|
255
248
|
}
|
|
256
249
|
if (processId) {
|
|
257
|
-
await this.terminateProcess(processId).catch(() => undefined);
|
|
250
|
+
await this.processRuntime.terminateProcess(processId).catch(() => undefined);
|
|
258
251
|
}
|
|
259
252
|
if (gitWorktreeCreated) {
|
|
260
253
|
await this.gitService.removeWorktree(worktreePath, repoPath, true).catch(() => undefined);
|
|
@@ -268,14 +261,9 @@ let WorktreesService = class WorktreesService {
|
|
|
268
261
|
}, 'Failed to clean up branch after create-worktree error'));
|
|
269
262
|
}
|
|
270
263
|
}
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (logContent.trim()) {
|
|
275
|
-
logger.error({ worktreeId: created.id, logContent: logContent.slice(-2000) }, 'Process runtime log before cleanup');
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
catch {
|
|
264
|
+
const crashLog = await this.processRuntime.readRecentLog(dataPath);
|
|
265
|
+
if (crashLog) {
|
|
266
|
+
logger.error({ worktreeId: created.id, logContent: crashLog }, 'Process runtime log before cleanup');
|
|
279
267
|
}
|
|
280
268
|
await (0, promises_1.rm)(dataPath, { recursive: true, force: true }).catch(() => undefined);
|
|
281
269
|
throw new common_1.BadRequestException(`Failed to create worktree: ${errorMessage}`);
|
|
@@ -307,6 +295,9 @@ let WorktreesService = class WorktreesService {
|
|
|
307
295
|
return this.buildWorktreeOverview(row);
|
|
308
296
|
}
|
|
309
297
|
async deleteWorktree(id, options = {}) {
|
|
298
|
+
return this.withOperationGuard(id, 'delete', () => this.executeDelete(id, options));
|
|
299
|
+
}
|
|
300
|
+
async executeDelete(id, options) {
|
|
310
301
|
const row = await this.requireWorktree(id);
|
|
311
302
|
const runtimeType = this.resolveRuntimeType(row.runtimeType);
|
|
312
303
|
const shouldDeleteBranch = options.deleteBranch ?? true;
|
|
@@ -317,19 +308,21 @@ let WorktreesService = class WorktreesService {
|
|
|
317
308
|
: null;
|
|
318
309
|
const dataPath = this.resolveDataPath(repoPath, row.name);
|
|
319
310
|
if (runtimeType === 'container' || row.containerId) {
|
|
320
|
-
await this.
|
|
311
|
+
await this.containerRuntime
|
|
321
312
|
.cleanupWorktreeProjectContainers(row.name, row.containerId)
|
|
322
313
|
.catch((error) => logger.warn({ error, worktreeId: row.id }, 'Failed cleaning project sub-containers'));
|
|
323
314
|
if (row.containerId) {
|
|
324
|
-
await this.
|
|
325
|
-
await this.
|
|
315
|
+
await this.containerRuntime.stopContainer(row.containerId).catch(() => undefined);
|
|
316
|
+
await this.containerRuntime.removeContainer(row.containerId, true).catch(() => undefined);
|
|
326
317
|
}
|
|
327
|
-
await this.
|
|
318
|
+
await this.containerRuntime
|
|
328
319
|
.removeWorktreeNetwork(row.name)
|
|
329
320
|
.catch((error) => logger.warn({ error, worktreeId: row.id }, 'Failed removing worktree docker network'));
|
|
330
321
|
}
|
|
331
322
|
else {
|
|
332
|
-
await this.
|
|
323
|
+
await this.processRuntime
|
|
324
|
+
.terminateProcess(row.processId)
|
|
325
|
+
.catch((error) => logger.warn({ error, worktreeId: row.id }, 'Failed stopping worktree process during delete'));
|
|
333
326
|
}
|
|
334
327
|
if (worktreePath) {
|
|
335
328
|
await this.gitService.removeWorktree(worktreePath, repoPath, true).catch(() => undefined);
|
|
@@ -357,6 +350,9 @@ let WorktreesService = class WorktreesService {
|
|
|
357
350
|
return { success: true };
|
|
358
351
|
}
|
|
359
352
|
async startWorktree(id) {
|
|
353
|
+
return this.withOperationGuard(id, 'start', () => this.executeStart(id));
|
|
354
|
+
}
|
|
355
|
+
async executeStart(id) {
|
|
360
356
|
const row = await this.requireWorktree(id);
|
|
361
357
|
const runtimeType = this.resolveRuntimeType(row.runtimeType);
|
|
362
358
|
if (runtimeType === 'process') {
|
|
@@ -369,7 +365,7 @@ let WorktreesService = class WorktreesService {
|
|
|
369
365
|
const dataPath = this.resolveDataPath(repoPath, row.name);
|
|
370
366
|
await (0, promises_1.mkdir)(dataPath, { recursive: true });
|
|
371
367
|
try {
|
|
372
|
-
const runtime = await this.startProcessRuntime({
|
|
368
|
+
const runtime = await this.processRuntime.startProcessRuntime({
|
|
373
369
|
worktreePath,
|
|
374
370
|
dataPath,
|
|
375
371
|
projectId,
|
|
@@ -394,18 +390,18 @@ let WorktreesService = class WorktreesService {
|
|
|
394
390
|
if (!row.containerId) {
|
|
395
391
|
throw new common_1.BadRequestException('Worktree has no container to start');
|
|
396
392
|
}
|
|
397
|
-
await this.
|
|
398
|
-
const healthy = await this.
|
|
393
|
+
await this.containerRuntime.startContainer(row.containerId);
|
|
394
|
+
const healthy = await this.containerRuntime.waitForHealthy(row.containerId, CONTAINER_HEALTH_TIMEOUT_MS);
|
|
399
395
|
if (!healthy) {
|
|
400
396
|
await this.tryUpdateStatus(row.id, 'error', {
|
|
401
397
|
errorMessage: 'Container failed readiness check after start',
|
|
402
398
|
});
|
|
403
399
|
throw new common_1.BadRequestException('Container started but failed readiness check');
|
|
404
400
|
}
|
|
405
|
-
await this.
|
|
401
|
+
await this.containerRuntime
|
|
406
402
|
.ensureWorktreeOnComposeNetwork(row.name, row.containerId)
|
|
407
403
|
.catch(() => undefined);
|
|
408
|
-
const hostPort = await this.
|
|
404
|
+
const hostPort = await this.containerRuntime
|
|
409
405
|
.getContainerHostPort(row.containerId)
|
|
410
406
|
.catch(() => null);
|
|
411
407
|
const updated = await this.tryUpdateStatus(row.id, 'running', {
|
|
@@ -415,10 +411,13 @@ let WorktreesService = class WorktreesService {
|
|
|
415
411
|
return this.toResponse(updated ?? row);
|
|
416
412
|
}
|
|
417
413
|
async stopWorktree(id) {
|
|
414
|
+
return this.withOperationGuard(id, 'stop', () => this.executeStop(id));
|
|
415
|
+
}
|
|
416
|
+
async executeStop(id) {
|
|
418
417
|
const row = await this.requireWorktree(id);
|
|
419
418
|
const runtimeType = this.resolveRuntimeType(row.runtimeType);
|
|
420
419
|
if (runtimeType === 'process') {
|
|
421
|
-
await this.terminateProcess(row.processId);
|
|
420
|
+
await this.processRuntime.terminateProcess(row.processId);
|
|
422
421
|
this.consecutiveHealthFailures.set(row.id, 0);
|
|
423
422
|
const updated = await this.tryUpdateStatus(row.id, 'stopped', {
|
|
424
423
|
processId: null,
|
|
@@ -432,7 +431,7 @@ let WorktreesService = class WorktreesService {
|
|
|
432
431
|
if (!row.containerId) {
|
|
433
432
|
throw new common_1.BadRequestException('Worktree has no container to stop');
|
|
434
433
|
}
|
|
435
|
-
await this.
|
|
434
|
+
await this.containerRuntime.stopContainer(row.containerId);
|
|
436
435
|
this.consecutiveHealthFailures.set(row.id, 0);
|
|
437
436
|
const updated = await this.tryUpdateStatus(row.id, 'stopped');
|
|
438
437
|
return this.toResponse(updated ?? row);
|
|
@@ -465,6 +464,9 @@ let WorktreesService = class WorktreesService {
|
|
|
465
464
|
};
|
|
466
465
|
}
|
|
467
466
|
async mergeWorktree(id) {
|
|
467
|
+
return this.withOperationGuard(id, 'merge', () => this.executeMerge(id));
|
|
468
|
+
}
|
|
469
|
+
async executeMerge(id) {
|
|
468
470
|
const row = await this.requireWorktree(id);
|
|
469
471
|
const currentStatus = String(row.status).toLowerCase();
|
|
470
472
|
if (currentStatus === 'merged') {
|
|
@@ -477,7 +479,7 @@ let WorktreesService = class WorktreesService {
|
|
|
477
479
|
const extractionRow = currentStatus === 'running' ? row : await this.ensureContainerReadyForTaskExtraction(row);
|
|
478
480
|
await this.extractTasksForMergedHistory(extractionRow);
|
|
479
481
|
if (row.containerId) {
|
|
480
|
-
await this.
|
|
482
|
+
await this.containerRuntime.stopContainer(row.containerId).catch(() => undefined);
|
|
481
483
|
}
|
|
482
484
|
const mergeResult = await this.gitService.executeMerge(row.repoPath, row.branchName, row.baseBranch, {
|
|
483
485
|
message: this.buildMergeCommitMessage(row),
|
|
@@ -511,6 +513,9 @@ let WorktreesService = class WorktreesService {
|
|
|
511
513
|
return this.toResponse(updated ?? row);
|
|
512
514
|
}
|
|
513
515
|
async rebaseWorktree(id) {
|
|
516
|
+
return this.withOperationGuard(id, 'rebase', () => this.executeRebase(id));
|
|
517
|
+
}
|
|
518
|
+
async executeRebase(id) {
|
|
514
519
|
const row = await this.requireWorktree(id);
|
|
515
520
|
const currentStatus = String(row.status).toLowerCase();
|
|
516
521
|
if (currentStatus === 'merged') {
|
|
@@ -521,7 +526,7 @@ let WorktreesService = class WorktreesService {
|
|
|
521
526
|
}
|
|
522
527
|
await this.assertCleanWorkingTree(row.worktreePath ?? row.repoPath, 'Rebase');
|
|
523
528
|
if (row.containerId) {
|
|
524
|
-
await this.
|
|
529
|
+
await this.containerRuntime.stopContainer(row.containerId).catch(() => undefined);
|
|
525
530
|
}
|
|
526
531
|
const rebaseResult = await this.gitService.executeRebase(row.worktreePath ?? row.repoPath, row.branchName, row.baseBranch);
|
|
527
532
|
if (!rebaseResult.success) {
|
|
@@ -544,8 +549,8 @@ let WorktreesService = class WorktreesService {
|
|
|
544
549
|
throw new common_1.BadRequestException(`Rebase failed: ${message}`);
|
|
545
550
|
}
|
|
546
551
|
if (row.containerId) {
|
|
547
|
-
await this.
|
|
548
|
-
const healthy = await this.
|
|
552
|
+
await this.containerRuntime.startContainer(row.containerId).catch(() => undefined);
|
|
553
|
+
const healthy = await this.containerRuntime.waitForHealthy(row.containerId, CONTAINER_HEALTH_TIMEOUT_MS);
|
|
549
554
|
if (!healthy) {
|
|
550
555
|
await this.tryUpdateStatus(row.id, 'error', {
|
|
551
556
|
errorMessage: 'Container failed readiness check after rebase',
|
|
@@ -631,8 +636,8 @@ let WorktreesService = class WorktreesService {
|
|
|
631
636
|
return false;
|
|
632
637
|
}
|
|
633
638
|
try {
|
|
634
|
-
await this.
|
|
635
|
-
const healthy = await this.
|
|
639
|
+
await this.containerRuntime.startContainer(row.containerId).catch(() => undefined);
|
|
640
|
+
const healthy = await this.containerRuntime.waitForHealthy(row.containerId, CONTAINER_HEALTH_TIMEOUT_MS);
|
|
636
641
|
if (!healthy) {
|
|
637
642
|
return false;
|
|
638
643
|
}
|
|
@@ -690,26 +695,13 @@ let WorktreesService = class WorktreesService {
|
|
|
690
695
|
async getWorktreeLogs(id, query) {
|
|
691
696
|
const row = await this.requireWorktree(id);
|
|
692
697
|
if (this.resolveRuntimeType(row.runtimeType) === 'process') {
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
if (error?.code === 'ENOENT') {
|
|
696
|
-
return '';
|
|
697
|
-
}
|
|
698
|
-
throw error;
|
|
699
|
-
});
|
|
700
|
-
const lines = content.split(/\r?\n/).filter((line, index, all) => {
|
|
701
|
-
if (line.length > 0) {
|
|
702
|
-
return true;
|
|
703
|
-
}
|
|
704
|
-
return index < all.length - 1;
|
|
705
|
-
});
|
|
706
|
-
const tailed = lines.slice(-query.tail).join('\n');
|
|
707
|
-
return { logs: tailed ? `${tailed}\n` : '' };
|
|
698
|
+
const dataPath = this.resolveDataPath(row.repoPath, row.name);
|
|
699
|
+
return { logs: await this.processRuntime.readLogs(dataPath, query.tail) };
|
|
708
700
|
}
|
|
709
701
|
if (!row.containerId) {
|
|
710
702
|
throw new common_1.BadRequestException('Worktree has no container');
|
|
711
703
|
}
|
|
712
|
-
const logs = await this.
|
|
704
|
+
const logs = await this.containerRuntime.getContainerLogs(row.containerId, query.tail);
|
|
713
705
|
return { logs };
|
|
714
706
|
}
|
|
715
707
|
async buildWorktreeOverview(row) {
|
|
@@ -794,10 +786,10 @@ let WorktreesService = class WorktreesService {
|
|
|
794
786
|
if (!row.containerId) {
|
|
795
787
|
return;
|
|
796
788
|
}
|
|
797
|
-
await this.
|
|
789
|
+
await this.containerRuntime
|
|
798
790
|
.ensureWorktreeOnComposeNetwork(row.name, row.containerId)
|
|
799
791
|
.catch(() => undefined);
|
|
800
|
-
const healthy = await this.
|
|
792
|
+
const healthy = await this.containerRuntime.waitForHealthy(row.containerId, HEALTH_MONITOR_PROBE_TIMEOUT_MS);
|
|
801
793
|
if (healthy) {
|
|
802
794
|
this.consecutiveHealthFailures.set(row.id, 0);
|
|
803
795
|
if (row.status === 'error') {
|
|
@@ -817,8 +809,12 @@ let WorktreesService = class WorktreesService {
|
|
|
817
809
|
}));
|
|
818
810
|
}
|
|
819
811
|
async monitorProcessWorktree(row) {
|
|
820
|
-
const
|
|
821
|
-
|
|
812
|
+
const verdict = await this.processRuntime.probeHealth({
|
|
813
|
+
pid: row.processId ?? null,
|
|
814
|
+
hostPort: row.containerPort ?? null,
|
|
815
|
+
runtimeToken: row.runtimeToken?.trim() || null,
|
|
816
|
+
});
|
|
817
|
+
if (verdict === 'dead' || verdict === 'token-mismatch') {
|
|
822
818
|
this.consecutiveHealthFailures.set(row.id, 0);
|
|
823
819
|
await this.tryUpdateStatus(row.id, 'stopped', {
|
|
824
820
|
processId: null,
|
|
@@ -829,30 +825,10 @@ let WorktreesService = class WorktreesService {
|
|
|
829
825
|
});
|
|
830
826
|
return;
|
|
831
827
|
}
|
|
832
|
-
|
|
833
|
-
const runtimeToken = row.runtimeToken?.trim() || null;
|
|
834
|
-
if (!hostPort || !runtimeToken) {
|
|
828
|
+
if (verdict === 'unreachable') {
|
|
835
829
|
await this.handleProcessProbeFailure(row.id, row.status);
|
|
836
830
|
return;
|
|
837
831
|
}
|
|
838
|
-
const healthy = await this.checkRuntimeReady(hostPort);
|
|
839
|
-
if (!healthy) {
|
|
840
|
-
await this.handleProcessProbeFailure(row.id, row.status);
|
|
841
|
-
return;
|
|
842
|
-
}
|
|
843
|
-
const runtimeMetadata = await this.fetchRuntimeMetadata(hostPort);
|
|
844
|
-
const runtimeTokenMatches = runtimeMetadata?.runtimeToken === runtimeToken;
|
|
845
|
-
if (!runtimeTokenMatches) {
|
|
846
|
-
this.consecutiveHealthFailures.set(row.id, 0);
|
|
847
|
-
await this.tryUpdateStatus(row.id, 'stopped', {
|
|
848
|
-
processId: null,
|
|
849
|
-
runtimeToken: null,
|
|
850
|
-
startedAt: null,
|
|
851
|
-
containerPort: null,
|
|
852
|
-
errorMessage: null,
|
|
853
|
-
});
|
|
854
|
-
return;
|
|
855
|
-
}
|
|
856
832
|
this.consecutiveHealthFailures.set(row.id, 0);
|
|
857
833
|
if (row.status === 'error') {
|
|
858
834
|
await this.tryUpdateStatus(row.id, 'running', {
|
|
@@ -874,7 +850,7 @@ let WorktreesService = class WorktreesService {
|
|
|
874
850
|
const candidates = rows.filter((row) => this.resolveRuntimeType(row.runtimeType) === 'process' && row.status === 'running');
|
|
875
851
|
await Promise.all(candidates.map(async (row) => {
|
|
876
852
|
const pid = row.processId ?? null;
|
|
877
|
-
if (!pid || !this.isProcessAlive(pid)) {
|
|
853
|
+
if (!pid || !this.processRuntime.isProcessAlive(pid)) {
|
|
878
854
|
await this.tryUpdateStatus(row.id, 'stopped', {
|
|
879
855
|
processId: null,
|
|
880
856
|
runtimeToken: null,
|
|
@@ -894,7 +870,7 @@ let WorktreesService = class WorktreesService {
|
|
|
894
870
|
});
|
|
895
871
|
return;
|
|
896
872
|
}
|
|
897
|
-
const metadata = await this.fetchRuntimeMetadata(row.containerPort);
|
|
873
|
+
const metadata = await this.processRuntime.fetchRuntimeMetadata(row.containerPort);
|
|
898
874
|
if (!metadata || metadata.runtimeToken !== row.runtimeToken) {
|
|
899
875
|
await this.tryUpdateStatus(row.id, 'stopped', {
|
|
900
876
|
processId: null,
|
|
@@ -909,217 +885,6 @@ let WorktreesService = class WorktreesService {
|
|
|
909
885
|
resolveRuntimeType(runtimeType) {
|
|
910
886
|
return runtimeType === 'process' ? 'process' : 'container';
|
|
911
887
|
}
|
|
912
|
-
async startProcessRuntime(input) {
|
|
913
|
-
const runtimeToken = (0, crypto_1.randomUUID)();
|
|
914
|
-
const portFilePath = (0, path_1.join)(input.dataPath, PROCESS_RUNTIME_PORT_FILE);
|
|
915
|
-
await (0, promises_1.rm)(portFilePath, { force: true }).catch(() => undefined);
|
|
916
|
-
const processId = await this.spawnProcessRuntime({
|
|
917
|
-
worktreePath: input.worktreePath,
|
|
918
|
-
dataPath: input.dataPath,
|
|
919
|
-
projectId: input.projectId,
|
|
920
|
-
runtimeToken,
|
|
921
|
-
});
|
|
922
|
-
const portInfo = await this.waitForRuntimePortFile(portFilePath, CONTAINER_HEALTH_TIMEOUT_MS, processId);
|
|
923
|
-
if (!portInfo) {
|
|
924
|
-
await this.terminateProcess(processId).catch(() => undefined);
|
|
925
|
-
throw new Error('Process runtime did not report its port before timeout');
|
|
926
|
-
}
|
|
927
|
-
if (portInfo.runtimeToken !== runtimeToken) {
|
|
928
|
-
await this.terminateProcess(processId).catch(() => undefined);
|
|
929
|
-
throw new Error(`Runtime port file token mismatch: expected ${runtimeToken}, ` +
|
|
930
|
-
`got ${portInfo.runtimeToken ?? 'none'}`);
|
|
931
|
-
}
|
|
932
|
-
const hostPort = portInfo.port;
|
|
933
|
-
const healthy = await this.waitForRuntimeHealthy(hostPort, CONTAINER_HEALTH_TIMEOUT_MS, processId);
|
|
934
|
-
if (!healthy) {
|
|
935
|
-
await this.terminateProcess(processId).catch(() => undefined);
|
|
936
|
-
throw new Error('Process runtime did not become healthy before timeout');
|
|
937
|
-
}
|
|
938
|
-
return { processId, hostPort, runtimeToken, startedAt: new Date() };
|
|
939
|
-
}
|
|
940
|
-
async spawnProcessRuntime(input) {
|
|
941
|
-
const cliPath = this.resolveCliPath();
|
|
942
|
-
const logPath = this.resolveProcessLogPath(input.dataPath);
|
|
943
|
-
const portFilePath = (0, path_1.join)(input.dataPath, PROCESS_RUNTIME_PORT_FILE);
|
|
944
|
-
await (0, promises_1.mkdir)(input.dataPath, { recursive: true });
|
|
945
|
-
const result = await this.executor.spawnDaemon({
|
|
946
|
-
argv: [
|
|
947
|
-
process.execPath,
|
|
948
|
-
cliPath,
|
|
949
|
-
'start',
|
|
950
|
-
'--foreground',
|
|
951
|
-
'--worktree-runtime',
|
|
952
|
-
'process',
|
|
953
|
-
'--port',
|
|
954
|
-
'0',
|
|
955
|
-
],
|
|
956
|
-
cwd: input.worktreePath,
|
|
957
|
-
logPath,
|
|
958
|
-
env: {
|
|
959
|
-
...process.env,
|
|
960
|
-
PORT: '0',
|
|
961
|
-
HOST: '127.0.0.1',
|
|
962
|
-
NODE_ENV: 'production',
|
|
963
|
-
DB_PATH: input.dataPath,
|
|
964
|
-
DB_FILENAME: PROCESS_DB_FILE_NAME,
|
|
965
|
-
DEVCHAIN_MODE: 'normal',
|
|
966
|
-
CONTAINER_PROJECT_ID: input.projectId,
|
|
967
|
-
RUNTIME_TOKEN: input.runtimeToken,
|
|
968
|
-
RUNTIME_PORT_FILE: portFilePath,
|
|
969
|
-
},
|
|
970
|
-
});
|
|
971
|
-
return result.pid;
|
|
972
|
-
}
|
|
973
|
-
async waitForRuntimeHealthy(hostPort, timeoutMs, pid) {
|
|
974
|
-
if (timeoutMs <= 0) {
|
|
975
|
-
return false;
|
|
976
|
-
}
|
|
977
|
-
const deadline = Date.now() + timeoutMs;
|
|
978
|
-
while (Date.now() < deadline) {
|
|
979
|
-
if (pid && !this.isProcessAlive(pid)) {
|
|
980
|
-
logger.warn({ pid, hostPort }, 'Child process exited during health polling');
|
|
981
|
-
return false;
|
|
982
|
-
}
|
|
983
|
-
const isReady = await this.checkRuntimeReady(hostPort);
|
|
984
|
-
if (isReady) {
|
|
985
|
-
return true;
|
|
986
|
-
}
|
|
987
|
-
await this.sleep(PROCESS_HEALTH_POLL_INTERVAL_MS);
|
|
988
|
-
}
|
|
989
|
-
return false;
|
|
990
|
-
}
|
|
991
|
-
async waitForRuntimePortFile(filePath, timeoutMs, pid) {
|
|
992
|
-
if (timeoutMs <= 0) {
|
|
993
|
-
return null;
|
|
994
|
-
}
|
|
995
|
-
const deadline = Date.now() + timeoutMs;
|
|
996
|
-
while (Date.now() < deadline) {
|
|
997
|
-
if (pid && !this.isProcessAlive(pid)) {
|
|
998
|
-
logger.warn({ pid, filePath }, 'Child process exited before writing port file');
|
|
999
|
-
return null;
|
|
1000
|
-
}
|
|
1001
|
-
try {
|
|
1002
|
-
const raw = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
1003
|
-
const parsed = JSON.parse(raw);
|
|
1004
|
-
if (typeof parsed.port === 'number' && parsed.port > 0) {
|
|
1005
|
-
return { port: parsed.port, runtimeToken: parsed.runtimeToken ?? null };
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
catch {
|
|
1009
|
-
}
|
|
1010
|
-
await this.sleep(PROCESS_HEALTH_POLL_INTERVAL_MS);
|
|
1011
|
-
}
|
|
1012
|
-
return null;
|
|
1013
|
-
}
|
|
1014
|
-
async checkRuntimeReady(hostPort) {
|
|
1015
|
-
const controller = new AbortController();
|
|
1016
|
-
const timeout = setTimeout(() => controller.abort(), PROCESS_RUNTIME_TIMEOUT_MS);
|
|
1017
|
-
try {
|
|
1018
|
-
const response = await fetch(`http://127.0.0.1:${hostPort}/health/ready`, {
|
|
1019
|
-
signal: controller.signal,
|
|
1020
|
-
});
|
|
1021
|
-
return response.ok;
|
|
1022
|
-
}
|
|
1023
|
-
catch {
|
|
1024
|
-
return false;
|
|
1025
|
-
}
|
|
1026
|
-
finally {
|
|
1027
|
-
clearTimeout(timeout);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
async fetchRuntimeMetadata(hostPort) {
|
|
1031
|
-
const controller = new AbortController();
|
|
1032
|
-
const timeout = setTimeout(() => controller.abort(), PROCESS_RUNTIME_TIMEOUT_MS);
|
|
1033
|
-
try {
|
|
1034
|
-
const response = await fetch(`http://127.0.0.1:${hostPort}/api/runtime`, {
|
|
1035
|
-
headers: { accept: 'application/json' },
|
|
1036
|
-
signal: controller.signal,
|
|
1037
|
-
});
|
|
1038
|
-
if (!response.ok) {
|
|
1039
|
-
return null;
|
|
1040
|
-
}
|
|
1041
|
-
return (await response.json());
|
|
1042
|
-
}
|
|
1043
|
-
catch {
|
|
1044
|
-
return null;
|
|
1045
|
-
}
|
|
1046
|
-
finally {
|
|
1047
|
-
clearTimeout(timeout);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
resolveCliPath() {
|
|
1051
|
-
const candidates = [
|
|
1052
|
-
(0, path_1.resolve)(process.cwd(), 'scripts', 'cli.js'),
|
|
1053
|
-
(0, path_1.resolve)(__dirname, '../../../../../../../../scripts/cli.js'),
|
|
1054
|
-
(0, path_1.resolve)(__dirname, '../../../../../../../scripts/cli.js'),
|
|
1055
|
-
(0, path_1.resolve)(__dirname, '../../../../../cli.js'),
|
|
1056
|
-
];
|
|
1057
|
-
if (process.argv[1] && !candidates.includes((0, path_1.resolve)(process.argv[1]))) {
|
|
1058
|
-
candidates.push((0, path_1.resolve)(process.argv[1]));
|
|
1059
|
-
}
|
|
1060
|
-
for (const candidate of candidates) {
|
|
1061
|
-
if ((0, fs_1.existsSync)(candidate)) {
|
|
1062
|
-
return candidate;
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
throw new Error('Unable to locate CLI entry point for process runtime start. ' +
|
|
1066
|
-
`Searched: ${candidates.join(', ')}`);
|
|
1067
|
-
}
|
|
1068
|
-
resolveProcessLogPath(dataPath) {
|
|
1069
|
-
return (0, path_1.join)(dataPath, PROCESS_LOG_FILE_NAME);
|
|
1070
|
-
}
|
|
1071
|
-
async terminateProcess(pid) {
|
|
1072
|
-
if (!pid) {
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
const stillRunningAfterSigterm = await this.signalProcessAndAwaitExit(pid, 'SIGTERM', PROCESS_SHUTDOWN_TIMEOUT_MS);
|
|
1076
|
-
if (!stillRunningAfterSigterm) {
|
|
1077
|
-
return;
|
|
1078
|
-
}
|
|
1079
|
-
await this.signalProcessAndAwaitExit(pid, 'SIGKILL', PROCESS_KILL_TIMEOUT_MS).catch((error) => {
|
|
1080
|
-
logger.warn({ error, pid }, 'Failed sending SIGKILL to worktree process');
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
async signalProcessAndAwaitExit(pid, signal, timeoutMs) {
|
|
1084
|
-
const signalPid = process.platform === 'win32' ? pid : -pid;
|
|
1085
|
-
try {
|
|
1086
|
-
process.kill(signalPid, signal);
|
|
1087
|
-
}
|
|
1088
|
-
catch (error) {
|
|
1089
|
-
const code = error.code;
|
|
1090
|
-
if (code === 'ESRCH') {
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1093
|
-
throw error;
|
|
1094
|
-
}
|
|
1095
|
-
const deadline = Date.now() + timeoutMs;
|
|
1096
|
-
while (Date.now() < deadline) {
|
|
1097
|
-
if (!this.isProcessAlive(pid)) {
|
|
1098
|
-
return false;
|
|
1099
|
-
}
|
|
1100
|
-
await this.sleep(200);
|
|
1101
|
-
}
|
|
1102
|
-
return this.isProcessAlive(pid);
|
|
1103
|
-
}
|
|
1104
|
-
isProcessAlive(pid) {
|
|
1105
|
-
try {
|
|
1106
|
-
process.kill(pid, 0);
|
|
1107
|
-
return true;
|
|
1108
|
-
}
|
|
1109
|
-
catch (error) {
|
|
1110
|
-
const code = error.code;
|
|
1111
|
-
if (code === 'ESRCH') {
|
|
1112
|
-
return false;
|
|
1113
|
-
}
|
|
1114
|
-
if (code === 'EPERM') {
|
|
1115
|
-
return true;
|
|
1116
|
-
}
|
|
1117
|
-
return false;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
async sleep(ms) {
|
|
1121
|
-
await new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
|
|
1122
|
-
}
|
|
1123
888
|
async handleContainerEvent(event) {
|
|
1124
889
|
const containerId = event.id;
|
|
1125
890
|
if (!containerId) {
|
|
@@ -1154,6 +919,20 @@ let WorktreesService = class WorktreesService {
|
|
|
1154
919
|
}
|
|
1155
920
|
return row;
|
|
1156
921
|
}
|
|
922
|
+
withOperationGuard(worktreeId, operation, run) {
|
|
923
|
+
const inFlight = this.inFlightOperations.get(worktreeId);
|
|
924
|
+
if (inFlight) {
|
|
925
|
+
if (inFlight.operation === operation) {
|
|
926
|
+
return inFlight.promise;
|
|
927
|
+
}
|
|
928
|
+
throw new common_1.ConflictException(`Worktree is already running an in-flight "${inFlight.operation}" operation`);
|
|
929
|
+
}
|
|
930
|
+
const promise = run().finally(() => {
|
|
931
|
+
this.inFlightOperations.delete(worktreeId);
|
|
932
|
+
});
|
|
933
|
+
this.inFlightOperations.set(worktreeId, { operation, promise });
|
|
934
|
+
return promise;
|
|
935
|
+
}
|
|
1157
936
|
async registerProjectInContainer(hostPort, input) {
|
|
1158
937
|
if (!hostPort) {
|
|
1159
938
|
throw new Error('Container did not expose a host port');
|
|
@@ -1475,13 +1254,13 @@ exports.WorktreesService = WorktreesService;
|
|
|
1475
1254
|
exports.WorktreesService = WorktreesService = __decorate([
|
|
1476
1255
|
(0, common_1.Injectable)(),
|
|
1477
1256
|
__param(0, (0, common_1.Inject)(worktrees_store_1.WORKTREES_STORE)),
|
|
1478
|
-
__param(6, (0, common_1.Optional)()),
|
|
1479
|
-
__param(6, (0, common_1.Inject)(storage_interface_1.STORAGE_SERVICE)),
|
|
1480
1257
|
__param(7, (0, common_1.Optional)()),
|
|
1481
|
-
|
|
1258
|
+
__param(7, (0, common_1.Inject)(storage_interface_1.STORAGE_SERVICE)),
|
|
1259
|
+
__metadata("design:paramtypes", [Object, container_runtime_1.ContainerRuntime,
|
|
1260
|
+
process_runtime_1.ProcessRuntime,
|
|
1482
1261
|
git_worktree_service_1.GitWorktreeService,
|
|
1483
1262
|
seed_preparation_service_1.SeedPreparationService,
|
|
1484
1263
|
event_emitter_1.EventEmitter2,
|
|
1485
|
-
event_log_service_1.EventLogService, Object
|
|
1264
|
+
event_log_service_1.EventLogService, Object])
|
|
1486
1265
|
], WorktreesService);
|
|
1487
1266
|
//# sourceMappingURL=worktrees.service.js.map
|