devchain-cli 0.9.2 → 0.10.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/cli.js +985 -194
- package/dist/drizzle/0044_supreme_joshua_kane.sql +57 -0
- package/dist/drizzle/0045_provider_auto_compact_threshold.sql +11 -0
- package/dist/drizzle/0046_worktrees_owner_project_id.sql +3 -0
- package/dist/drizzle/meta/0044_snapshot.json +4620 -0
- package/dist/drizzle/meta/_journal.json +22 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +18 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts.map +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js +6 -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/app.main.module.d.ts +4 -0
- package/dist/server/app.main.module.js +102 -0
- package/dist/server/app.main.module.js.map +1 -0
- package/dist/server/app.module.d.ts +1 -4
- package/dist/server/app.module.js +2 -78
- package/dist/server/app.module.js.map +1 -1
- package/dist/server/app.normal.module.d.ts +4 -0
- package/dist/server/app.normal.module.js +90 -0
- package/dist/server/app.normal.module.js.map +1 -0
- package/dist/server/common/config/env.config.d.ts +81 -1
- package/dist/server/common/config/env.config.js +52 -2
- package/dist/server/common/config/env.config.js.map +1 -1
- package/dist/server/common/templates-directory.d.ts +8 -0
- package/dist/server/common/templates-directory.js +56 -0
- package/dist/server/common/templates-directory.js.map +1 -0
- package/dist/server/main.js +58 -7
- package/dist/server/main.js.map +1 -1
- package/dist/server/modules/chat/dtos/chat.dto.d.ts +2 -2
- package/dist/server/modules/core/controllers/health.controller.d.ts +4 -0
- package/dist/server/modules/core/controllers/health.controller.js +22 -1
- package/dist/server/modules/core/controllers/health.controller.js.map +1 -1
- package/dist/server/modules/core/controllers/runtime.controller.d.ts +18 -0
- package/dist/server/modules/core/controllers/runtime.controller.js +130 -0
- package/dist/server/modules/core/controllers/runtime.controller.js.map +1 -0
- package/dist/server/modules/core/core-common.module.d.ts +2 -0
- package/dist/server/modules/core/core-common.module.js +24 -0
- package/dist/server/modules/core/core-common.module.js.map +1 -0
- package/dist/server/modules/core/core-main-health.module.d.ts +2 -0
- package/dist/server/modules/core/core-main-health.module.js +32 -0
- package/dist/server/modules/core/core-main-health.module.js.map +1 -0
- package/dist/server/modules/core/core-normal-health.module.d.ts +2 -0
- package/dist/server/modules/core/core-normal-health.module.js +29 -0
- package/dist/server/modules/core/core-normal-health.module.js.map +1 -0
- package/dist/server/modules/core/core-normal.module.d.ts +2 -0
- package/dist/server/modules/core/core-normal.module.js +28 -0
- package/dist/server/modules/core/core-normal.module.js.map +1 -0
- package/dist/server/modules/core/core.module.js +4 -11
- package/dist/server/modules/core/core.module.js.map +1 -1
- package/dist/server/modules/core/services/health.service.d.ts +13 -0
- package/dist/server/modules/core/services/health.service.js +39 -0
- package/dist/server/modules/core/services/health.service.js.map +1 -0
- package/dist/server/modules/core/services/main-readiness-checker.service.d.ts +14 -0
- package/dist/server/modules/core/services/main-readiness-checker.service.js +82 -0
- package/dist/server/modules/core/services/main-readiness-checker.service.js.map +1 -0
- package/dist/server/modules/core/services/normal-readiness-checker.service.d.ts +13 -0
- package/dist/server/modules/core/services/normal-readiness-checker.service.js +67 -0
- package/dist/server/modules/core/services/normal-readiness-checker.service.js.map +1 -0
- package/dist/server/modules/core/services/preflight.service.d.ts +1 -0
- package/dist/server/modules/core/services/preflight.service.js +18 -1
- package/dist/server/modules/core/services/preflight.service.js.map +1 -1
- package/dist/server/modules/core/services/provider-mcp-ensure.service.js +8 -0
- package/dist/server/modules/core/services/provider-mcp-ensure.service.js.map +1 -1
- package/dist/server/modules/epics/epics.module.js +2 -2
- package/dist/server/modules/epics/epics.module.js.map +1 -1
- package/dist/server/modules/events/catalog/claude.hooks.session.started.d.ts +39 -0
- package/dist/server/modules/events/catalog/claude.hooks.session.started.js +20 -0
- package/dist/server/modules/events/catalog/claude.hooks.session.started.js.map +1 -0
- package/dist/server/modules/events/catalog/epic.created.d.ts +2 -2
- package/dist/server/modules/events/catalog/index.d.ts +38 -4
- package/dist/server/modules/events/catalog/index.js +2 -0
- package/dist/server/modules/events/catalog/index.js.map +1 -1
- package/dist/server/modules/events/catalog/terminal.watcher.triggered.d.ts +2 -2
- package/dist/server/modules/events/controllers/event-log.controller.d.ts +1 -1
- package/dist/server/modules/events/controllers/event-log.controller.js +11 -9
- package/dist/server/modules/events/controllers/event-log.controller.js.map +1 -1
- package/dist/server/modules/events/dtos/event-log.dto.d.ts +1 -0
- package/dist/server/modules/events/events-domain.module.d.ts +2 -0
- package/dist/server/modules/events/events-domain.module.js +42 -0
- package/dist/server/modules/events/events-domain.module.js.map +1 -0
- package/dist/server/modules/events/events-infra.module.d.ts +2 -0
- package/dist/server/modules/events/events-infra.module.js +26 -0
- package/dist/server/modules/events/events-infra.module.js.map +1 -0
- package/dist/server/modules/events/events.module.js +4 -27
- package/dist/server/modules/events/events.module.js.map +1 -1
- package/dist/server/modules/events/index.d.ts +2 -0
- package/dist/server/modules/events/index.js +2 -0
- package/dist/server/modules/events/index.js.map +1 -1
- package/dist/server/modules/events/services/event-log.service.d.ts +8 -1
- package/dist/server/modules/events/services/event-log.service.js +41 -0
- package/dist/server/modules/events/services/event-log.service.js.map +1 -1
- package/dist/server/modules/events/subscribers/index.js +2 -0
- package/dist/server/modules/events/subscribers/index.js.map +1 -1
- package/dist/server/modules/events/subscribers/worktree-broadcaster.subscriber.d.ts +8 -0
- package/dist/server/modules/events/subscribers/worktree-broadcaster.subscriber.js +48 -0
- package/dist/server/modules/events/subscribers/worktree-broadcaster.subscriber.js.map +1 -0
- package/dist/server/modules/git/dtos/git.dto.d.ts +1 -1
- package/dist/server/modules/guests/guests.module.js +2 -2
- package/dist/server/modules/guests/guests.module.js.map +1 -1
- package/dist/server/modules/hooks/controllers/hooks.controller.d.ts +7 -0
- package/dist/server/modules/hooks/controllers/hooks.controller.js +49 -0
- package/dist/server/modules/hooks/controllers/hooks.controller.js.map +1 -0
- package/dist/server/modules/hooks/dtos/hook-event.dto.d.ts +41 -0
- package/dist/server/modules/hooks/dtos/hook-event.dto.js +19 -0
- package/dist/server/modules/hooks/dtos/hook-event.dto.js.map +1 -0
- package/dist/server/modules/hooks/hooks.module.d.ts +2 -0
- package/dist/server/modules/hooks/hooks.module.js +27 -0
- package/dist/server/modules/hooks/hooks.module.js.map +1 -0
- package/dist/server/modules/hooks/services/hooks-config.service.d.ts +5 -0
- package/dist/server/modules/hooks/services/hooks-config.service.js +215 -0
- package/dist/server/modules/hooks/services/hooks-config.service.js.map +1 -0
- package/dist/server/modules/hooks/services/hooks.service.d.ts +11 -0
- package/dist/server/modules/hooks/services/hooks.service.js +83 -0
- package/dist/server/modules/hooks/services/hooks.service.js.map +1 -0
- package/dist/server/modules/mcp/dtos/mcp.dto.d.ts +14 -14
- package/dist/server/modules/mcp/mcp.module.js +2 -2
- package/dist/server/modules/mcp/mcp.module.js.map +1 -1
- package/dist/server/modules/orchestrator/docker/docker.module.d.ts +2 -0
- package/dist/server/modules/orchestrator/docker/docker.module.js +22 -0
- package/dist/server/modules/orchestrator/docker/docker.module.js.map +1 -0
- package/dist/server/modules/orchestrator/docker/index.d.ts +3 -0
- package/dist/server/modules/orchestrator/docker/index.js +20 -0
- package/dist/server/modules/orchestrator/docker/index.js.map +1 -0
- package/dist/server/modules/orchestrator/docker/services/docker.service.d.ts +85 -0
- package/dist/server/modules/orchestrator/docker/services/docker.service.js +745 -0
- package/dist/server/modules/orchestrator/docker/services/docker.service.js.map +1 -0
- package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.d.ts +11 -0
- package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.js +181 -0
- package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.js.map +1 -0
- package/dist/server/modules/orchestrator/git/controllers/git.controller.d.ts +8 -0
- package/dist/server/modules/orchestrator/git/controllers/git.controller.js +38 -0
- package/dist/server/modules/orchestrator/git/controllers/git.controller.js.map +1 -0
- package/dist/server/modules/orchestrator/git/git.module.d.ts +2 -0
- package/dist/server/modules/orchestrator/git/git.module.js +23 -0
- package/dist/server/modules/orchestrator/git/git.module.js.map +1 -0
- package/dist/server/modules/orchestrator/git/index.d.ts +3 -0
- package/dist/server/modules/orchestrator/git/index.js +20 -0
- package/dist/server/modules/orchestrator/git/index.js.map +1 -0
- package/dist/server/modules/orchestrator/git/services/git-worktree.service.d.ts +83 -0
- package/dist/server/modules/orchestrator/git/services/git-worktree.service.js +474 -0
- package/dist/server/modules/orchestrator/git/services/git-worktree.service.js.map +1 -0
- package/dist/server/modules/orchestrator/index.d.ts +6 -0
- package/dist/server/modules/orchestrator/index.js +23 -0
- package/dist/server/modules/orchestrator/index.js.map +1 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/db/index.d.ts +1 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/db/index.js +18 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/db/index.js.map +1 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/db/orchestrator.provider.d.ts +5 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/db/orchestrator.provider.js +10 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/db/orchestrator.provider.js.map +1 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/index.d.ts +2 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/index.js +19 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/index.js.map +1 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/orchestrator-storage.module.d.ts +2 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/orchestrator-storage.module.js +23 -0
- package/dist/server/modules/orchestrator/orchestrator-storage/orchestrator-storage.module.js.map +1 -0
- package/dist/server/modules/orchestrator/proxy/index.d.ts +2 -0
- package/dist/server/modules/orchestrator/proxy/index.js +19 -0
- package/dist/server/modules/orchestrator/proxy/index.js.map +1 -0
- package/dist/server/modules/orchestrator/proxy/orchestrator-proxy.module.d.ts +2 -0
- package/dist/server/modules/orchestrator/proxy/orchestrator-proxy.module.js +22 -0
- package/dist/server/modules/orchestrator/proxy/orchestrator-proxy.module.js.map +1 -0
- package/dist/server/modules/orchestrator/proxy/services/orchestrator-proxy.service.d.ts +18 -0
- package/dist/server/modules/orchestrator/proxy/services/orchestrator-proxy.service.js +192 -0
- package/dist/server/modules/orchestrator/proxy/services/orchestrator-proxy.service.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/controllers/overview.controller.d.ts +9 -0
- package/dist/server/modules/orchestrator/sync/controllers/overview.controller.js +66 -0
- package/dist/server/modules/orchestrator/sync/controllers/overview.controller.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/dtos/overview.dto.d.ts +52 -0
- package/dist/server/modules/orchestrator/sync/dtos/overview.dto.js +3 -0
- package/dist/server/modules/orchestrator/sync/dtos/overview.dto.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/dtos/task-merge.dto.d.ts +5 -0
- package/dist/server/modules/orchestrator/sync/dtos/task-merge.dto.js +3 -0
- package/dist/server/modules/orchestrator/sync/dtos/task-merge.dto.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/events/task-merge.events.d.ts +4 -0
- package/dist/server/modules/orchestrator/sync/events/task-merge.events.js +5 -0
- package/dist/server/modules/orchestrator/sync/events/task-merge.events.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/index.d.ts +7 -0
- package/dist/server/modules/orchestrator/sync/index.js +24 -0
- package/dist/server/modules/orchestrator/sync/index.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/services/lazy-fetch.service.d.ts +31 -0
- package/dist/server/modules/orchestrator/sync/services/lazy-fetch.service.js +410 -0
- package/dist/server/modules/orchestrator/sync/services/lazy-fetch.service.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/services/task-merge.service.d.ts +44 -0
- package/dist/server/modules/orchestrator/sync/services/task-merge.service.js +730 -0
- package/dist/server/modules/orchestrator/sync/services/task-merge.service.js.map +1 -0
- package/dist/server/modules/orchestrator/sync/sync.module.d.ts +2 -0
- package/dist/server/modules/orchestrator/sync/sync.module.js +36 -0
- package/dist/server/modules/orchestrator/sync/sync.module.js.map +1 -0
- package/dist/server/modules/orchestrator/ui/app/lib/worktrees.d.ts +118 -0
- package/dist/server/modules/orchestrator/ui/app/lib/worktrees.js +297 -0
- package/dist/server/modules/orchestrator/ui/app/lib/worktrees.js.map +1 -0
- package/dist/server/modules/orchestrator/ui/app/orchestrator-app.d.ts +17 -0
- package/dist/server/modules/orchestrator/ui/app/orchestrator-app.js +752 -0
- package/dist/server/modules/orchestrator/ui/app/orchestrator-app.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/controllers/templates.controller.d.ts +15 -0
- package/dist/server/modules/orchestrator/worktrees/controllers/templates.controller.js +85 -0
- package/dist/server/modules/orchestrator/worktrees/controllers/templates.controller.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/controllers/worktrees.controller.d.ts +29 -0
- package/dist/server/modules/orchestrator/worktrees/controllers/worktrees.controller.js +272 -0
- package/dist/server/modules/orchestrator/worktrees/controllers/worktrees.controller.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/dtos/worktree.dto.d.ts +109 -0
- package/dist/server/modules/orchestrator/worktrees/dtos/worktree.dto.js +57 -0
- package/dist/server/modules/orchestrator/worktrees/dtos/worktree.dto.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/events/worktree.events.d.ts +4 -0
- package/dist/server/modules/orchestrator/worktrees/events/worktree.events.js +5 -0
- package/dist/server/modules/orchestrator/worktrees/events/worktree.events.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/index.d.ts +7 -0
- package/dist/server/modules/orchestrator/worktrees/index.js +24 -0
- package/dist/server/modules/orchestrator/worktrees/index.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/local-worktrees.store.d.ts +18 -0
- package/dist/server/modules/orchestrator/worktrees/local-worktrees.store.js +198 -0
- package/dist/server/modules/orchestrator/worktrees/local-worktrees.store.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/services/worktrees.service.d.ts +87 -0
- package/dist/server/modules/orchestrator/worktrees/services/worktrees.service.js +1380 -0
- package/dist/server/modules/orchestrator/worktrees/services/worktrees.service.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/worktree-validation.d.ts +4 -0
- package/dist/server/modules/orchestrator/worktrees/worktree-validation.js +43 -0
- package/dist/server/modules/orchestrator/worktrees/worktree-validation.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.module.d.ts +2 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.module.js +44 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.module.js.map +1 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.store.d.ts +38 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.store.js +5 -0
- package/dist/server/modules/orchestrator/worktrees/worktrees.store.js.map +1 -0
- package/dist/server/modules/profiles/dto.d.ts +4 -4
- package/dist/server/modules/projects/controllers/projects.controller.d.ts +13 -3
- package/dist/server/modules/projects/controllers/projects.controller.js +55 -7
- package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
- package/dist/server/modules/projects/projects.module.js +3 -2
- package/dist/server/modules/projects/projects.module.js.map +1 -1
- package/dist/server/modules/projects/services/main-project-bootstrap.service.d.ts +11 -0
- package/dist/server/modules/projects/services/main-project-bootstrap.service.js +76 -0
- package/dist/server/modules/projects/services/main-project-bootstrap.service.js.map +1 -0
- package/dist/server/modules/projects/services/projects.service.d.ts +8 -0
- package/dist/server/modules/projects/services/projects.service.js +115 -37
- package/dist/server/modules/projects/services/projects.service.js.map +1 -1
- package/dist/server/modules/providers/adapters/gemini.adapter.d.ts +1 -1
- package/dist/server/modules/providers/adapters/gemini.adapter.js +6 -4
- package/dist/server/modules/providers/adapters/gemini.adapter.js.map +1 -1
- package/dist/server/modules/providers/controllers/providers.controller.d.ts +3 -0
- package/dist/server/modules/providers/controllers/providers.controller.js +28 -0
- package/dist/server/modules/providers/controllers/providers.controller.js.map +1 -1
- package/dist/server/modules/providers/providers.module.js +2 -2
- package/dist/server/modules/providers/providers.module.js.map +1 -1
- package/dist/server/modules/registry/services/unified-template.service.js +6 -18
- package/dist/server/modules/registry/services/unified-template.service.js.map +1 -1
- package/dist/server/modules/reviews/dtos/review.dto.d.ts +4 -4
- package/dist/server/modules/reviews/reviews.module.js +2 -2
- package/dist/server/modules/reviews/reviews.module.js.map +1 -1
- package/dist/server/modules/seeders/seeders/0005_seed_renew_instructions_subscriber.d.ts +3 -0
- package/dist/server/modules/seeders/seeders/0005_seed_renew_instructions_subscriber.js +89 -0
- package/dist/server/modules/seeders/seeders/0005_seed_renew_instructions_subscriber.js.map +1 -0
- package/dist/server/modules/seeders/seeders/0006_seed_rename_template_slugs.d.ts +3 -0
- package/dist/server/modules/seeders/seeders/0006_seed_rename_template_slugs.js +60 -0
- package/dist/server/modules/seeders/seeders/0006_seed_rename_template_slugs.js.map +1 -0
- package/dist/server/modules/seeders/services/data-seeder.service.js +4 -0
- package/dist/server/modules/seeders/services/data-seeder.service.js.map +1 -1
- package/dist/server/modules/sessions/services/sessions.service.d.ts +3 -1
- package/dist/server/modules/sessions/services/sessions.service.js +79 -22
- package/dist/server/modules/sessions/services/sessions.service.js.map +1 -1
- package/dist/server/modules/sessions/sessions.module.js +6 -4
- package/dist/server/modules/sessions/sessions.module.js.map +1 -1
- package/dist/server/modules/sessions/utils/claude-config.d.ts +6 -2
- package/dist/server/modules/sessions/utils/claude-config.js +19 -6
- package/dist/server/modules/sessions/utils/claude-config.js.map +1 -1
- package/dist/server/modules/settings/dtos/settings.dto.d.ts +4 -4
- package/dist/server/modules/skills/dtos/community-sources.dto.d.ts +2 -2
- package/dist/server/modules/skills/dtos/local-sources.dto.d.ts +2 -2
- package/dist/server/modules/skills/dtos/skill.dto.d.ts +7 -7
- package/dist/server/modules/storage/db/schema.d.ts +811 -0
- package/dist/server/modules/storage/db/schema.js +63 -1
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/db/sqlite-json.d.ts +2 -0
- package/dist/server/modules/storage/db/sqlite-json.js +8 -0
- package/dist/server/modules/storage/db/sqlite-json.js.map +1 -0
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +4 -1
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/local-storage.service.d.ts +1 -1
- package/dist/server/modules/storage/local/local-storage.service.js +19 -2
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +2 -0
- package/dist/server/modules/subscribers/dtos/subscriber.dto.d.ts +16 -16
- package/dist/server/modules/subscribers/events/event-fields-catalog.js +18 -0
- package/dist/server/modules/subscribers/events/event-fields-catalog.js.map +1 -1
- package/dist/server/modules/subscribers/subscribers.module.js +2 -2
- package/dist/server/modules/subscribers/subscribers.module.js.map +1 -1
- package/dist/server/modules/terminal/gateways/terminal.gateway.js +7 -2
- package/dist/server/modules/terminal/gateways/terminal.gateway.js.map +1 -1
- package/dist/server/modules/terminal/services/tmux.service.d.ts +9 -0
- package/dist/server/modules/terminal/services/tmux.service.js +55 -5
- package/dist/server/modules/terminal/services/tmux.service.js.map +1 -1
- package/dist/server/modules/terminal/terminal.module.js +2 -2
- package/dist/server/modules/terminal/terminal.module.js.map +1 -1
- package/dist/server/modules/watchers/watchers.module.js +2 -2
- package/dist/server/modules/watchers/watchers.module.js.map +1 -1
- package/dist/server/templates/3-agents-dev.json +662 -0
- package/dist/server/templates/{dev-loop.json → 5-agents-dev.json} +174 -100
- package/dist/server/test-setup.js +7 -0
- package/dist/server/test-setup.js.map +1 -1
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/ReviewDetailPage-CZZQtaY7.js +1 -0
- package/dist/server/ui/assets/{ReviewsPage-MKT-vv59.js → ReviewsPage-C209GLQG.js} +1 -1
- package/dist/server/ui/assets/index-DvRuLfpZ.css +32 -0
- package/dist/server/ui/assets/index-Th1FDtKR.js +977 -0
- package/dist/server/ui/assets/{useReviewSubscription-Dc58i6Bk.js → useReviewSubscription-Dcabsa78.js} +1 -1
- package/dist/server/ui/index.html +2 -2
- package/dist/templates/3-agents-dev.json +662 -0
- package/dist/templates/{dev-loop.json → 5-agents-dev.json} +174 -100
- package/package.json +15 -1
- package/dist/server/ui/assets/ReviewDetailPage-BvSckWKj.js +0 -6
- package/dist/server/ui/assets/index-BtUq-Qxb.css +0 -32
- package/dist/server/ui/assets/index-kTb634Zp.js +0 -945
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.TaskMergeService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const core_1 = require("@nestjs/core");
|
|
18
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
19
|
+
const crypto_1 = require("crypto");
|
|
20
|
+
const logger_1 = require("../../../../common/logging/logger");
|
|
21
|
+
const env_config_1 = require("../../../../common/config/env.config");
|
|
22
|
+
const orchestrator_provider_1 = require("../../orchestrator-storage/db/orchestrator.provider");
|
|
23
|
+
const schema_1 = require("../../../storage/db/schema");
|
|
24
|
+
const worktrees_store_1 = require("../../worktrees/worktrees.store");
|
|
25
|
+
const task_merge_events_1 = require("../events/task-merge.events");
|
|
26
|
+
const sqlite_raw_1 = require("../../../storage/db/sqlite-raw");
|
|
27
|
+
const main_project_bootstrap_service_1 = require("../../../projects/services/main-project-bootstrap.service");
|
|
28
|
+
const storage_interface_1 = require("../../../storage/interfaces/storage.interface");
|
|
29
|
+
const path_1 = require("path");
|
|
30
|
+
const logger = (0, logger_1.createLogger)('OrchestratorTaskMergeService');
|
|
31
|
+
const CONTAINER_FETCH_TIMEOUT_MS = 5_000;
|
|
32
|
+
const UNKNOWN_STATUS_LABEL = 'Unknown';
|
|
33
|
+
const UNKNOWN_STATUS_COLOR = '#6c757d';
|
|
34
|
+
const UNKNOWN_PROFILE_LABEL = 'Unknown';
|
|
35
|
+
const SQLITE_EPIC_PAGE_SIZE = 500;
|
|
36
|
+
const SQLITE_STATUS_PAGE_SIZE = 500;
|
|
37
|
+
const SQLITE_AGENT_PAGE_SIZE = 500;
|
|
38
|
+
const MERGED_TAG_PREFIX = 'merged:';
|
|
39
|
+
let TaskMergeService = class TaskMergeService {
|
|
40
|
+
constructor(store, db, storage, mainProjectBootstrap, moduleRef) {
|
|
41
|
+
this.store = store;
|
|
42
|
+
this.db = db;
|
|
43
|
+
this.storage = storage;
|
|
44
|
+
this.mainProjectBootstrap = mainProjectBootstrap;
|
|
45
|
+
this.moduleRef = moduleRef;
|
|
46
|
+
this.sqliteMergeImportQueue = Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
async handleTaskMergeRequested(payload) {
|
|
49
|
+
return this.mergeTasksFromContainer(payload.worktreeId);
|
|
50
|
+
}
|
|
51
|
+
async mergeTasksFromContainer(worktreeId) {
|
|
52
|
+
const worktree = await this.store.getById(worktreeId);
|
|
53
|
+
if (!worktree) {
|
|
54
|
+
throw new common_1.NotFoundException(`Worktree not found: ${worktreeId}`);
|
|
55
|
+
}
|
|
56
|
+
if (!worktree.containerPort || !worktree.devchainProjectId) {
|
|
57
|
+
throw new common_1.BadRequestException(`Worktree ${worktreeId} has no active container endpoint for task extraction`);
|
|
58
|
+
}
|
|
59
|
+
const baseUrl = `http://127.0.0.1:${worktree.containerPort}`;
|
|
60
|
+
const projectId = encodeURIComponent(worktree.devchainProjectId);
|
|
61
|
+
let epicsPayload;
|
|
62
|
+
let agentsPayload;
|
|
63
|
+
let statusesPayload;
|
|
64
|
+
let profilesPayload;
|
|
65
|
+
try {
|
|
66
|
+
[epicsPayload, agentsPayload, statusesPayload, profilesPayload] = await Promise.all([
|
|
67
|
+
this.fetchContainerJson(`${baseUrl}/api/epics?projectId=${projectId}&limit=1000&type=all`),
|
|
68
|
+
this.fetchContainerJson(`${baseUrl}/api/agents?projectId=${projectId}&limit=1000`),
|
|
69
|
+
this.fetchContainerJsonSafe(`${baseUrl}/api/statuses?projectId=${projectId}&limit=1000`),
|
|
70
|
+
this.fetchProfilesForProject(baseUrl, projectId),
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
throw new common_1.BadRequestException(`Failed to extract task history from worktree container ${worktree.name}: ${message}`);
|
|
76
|
+
}
|
|
77
|
+
const nowIso = new Date().toISOString();
|
|
78
|
+
const epics = this.normalizeEpics(epicsPayload.items ?? []);
|
|
79
|
+
const agents = this.normalizeAgents(agentsPayload.items ?? []);
|
|
80
|
+
const agentNameById = new Map(agents.map((agent) => [agent.id, agent.name]));
|
|
81
|
+
const statusById = this.buildStatusMap(statusesPayload?.items ?? []);
|
|
82
|
+
const profileNameById = this.buildProfileMap(profilesPayload?.items ?? []);
|
|
83
|
+
const assignedEpicsByAgent = new Map();
|
|
84
|
+
for (const epic of epics) {
|
|
85
|
+
if (!epic.agentId) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
assignedEpicsByAgent.set(epic.agentId, (assignedEpicsByAgent.get(epic.agentId) ?? 0) + 1);
|
|
89
|
+
}
|
|
90
|
+
const mergedEpicRows = epics.map((epic) => {
|
|
91
|
+
const resolvedStatus = this.resolveStatus(epic.statusId, statusById);
|
|
92
|
+
return {
|
|
93
|
+
id: (0, crypto_1.randomUUID)(),
|
|
94
|
+
worktreeId: worktree.id,
|
|
95
|
+
devchainEpicId: epic.id,
|
|
96
|
+
title: epic.title,
|
|
97
|
+
description: epic.description,
|
|
98
|
+
statusName: resolvedStatus.label,
|
|
99
|
+
statusColor: resolvedStatus.color,
|
|
100
|
+
agentName: epic.agentId ? (agentNameById.get(epic.agentId) ?? null) : null,
|
|
101
|
+
parentEpicId: epic.parentId,
|
|
102
|
+
tags: epic.tags,
|
|
103
|
+
createdAtSource: epic.createdAtSource,
|
|
104
|
+
mergedAt: nowIso,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
const mergedAgentRows = agents.map((agent) => ({
|
|
108
|
+
id: (0, crypto_1.randomUUID)(),
|
|
109
|
+
worktreeId: worktree.id,
|
|
110
|
+
devchainAgentId: agent.id,
|
|
111
|
+
name: agent.name,
|
|
112
|
+
profileName: this.resolveProfileName(agent.profileId, profileNameById),
|
|
113
|
+
epicsCompleted: agent.epicsCompleted ??
|
|
114
|
+
agent.completedEpics ??
|
|
115
|
+
agent.activityCount ??
|
|
116
|
+
assignedEpicsByAgent.get(agent.id) ??
|
|
117
|
+
0,
|
|
118
|
+
mergedAt: nowIso,
|
|
119
|
+
}));
|
|
120
|
+
await this.persistMergedRows(mergedEpicRows, mergedAgentRows);
|
|
121
|
+
const sqliteImportSummary = await this.importEpicsIntoMainProject({
|
|
122
|
+
worktreeId: worktree.id,
|
|
123
|
+
worktreeName: worktree.name,
|
|
124
|
+
epics,
|
|
125
|
+
statusById,
|
|
126
|
+
agentNameById,
|
|
127
|
+
});
|
|
128
|
+
logger.info({
|
|
129
|
+
worktreeId: worktree.id,
|
|
130
|
+
worktreeName: worktree.name,
|
|
131
|
+
epicsMerged: mergedEpicRows.length,
|
|
132
|
+
agentsMerged: mergedAgentRows.length,
|
|
133
|
+
sqliteEpicsImported: sqliteImportSummary.imported,
|
|
134
|
+
sqliteEpicsSkipped: sqliteImportSummary.skipped,
|
|
135
|
+
sqliteStatusesCreated: sqliteImportSummary.statusesCreated,
|
|
136
|
+
}, 'Merged task history from container into orchestrator storage');
|
|
137
|
+
return {
|
|
138
|
+
worktreeId: worktree.id,
|
|
139
|
+
epicsMerged: mergedEpicRows.length,
|
|
140
|
+
agentsMerged: mergedAgentRows.length,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async persistMergedRows(mergedEpicRows, mergedAgentRows) {
|
|
144
|
+
const persist = async (targetDb) => {
|
|
145
|
+
if (mergedEpicRows.length > 0) {
|
|
146
|
+
await targetDb
|
|
147
|
+
.insert(schema_1.mergedEpics)
|
|
148
|
+
.values(mergedEpicRows)
|
|
149
|
+
.onConflictDoNothing({
|
|
150
|
+
target: [schema_1.mergedEpics.worktreeId, schema_1.mergedEpics.devchainEpicId],
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (mergedAgentRows.length > 0) {
|
|
154
|
+
await targetDb
|
|
155
|
+
.insert(schema_1.mergedAgents)
|
|
156
|
+
.values(mergedAgentRows)
|
|
157
|
+
.onConflictDoNothing({
|
|
158
|
+
target: [schema_1.mergedAgents.worktreeId, schema_1.mergedAgents.devchainAgentId],
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const rawSqlite = this.resolveRawSqliteClientForOrchestratorDb();
|
|
163
|
+
if (!rawSqlite) {
|
|
164
|
+
const dbWithTransaction = this.db;
|
|
165
|
+
if (typeof dbWithTransaction.transaction === 'function') {
|
|
166
|
+
await dbWithTransaction.transaction(async (tx) => {
|
|
167
|
+
await persist(tx);
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await persist(this.db);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await this.runWithSqliteMergeLock(async () => {
|
|
175
|
+
rawSqlite.exec('BEGIN IMMEDIATE TRANSACTION');
|
|
176
|
+
try {
|
|
177
|
+
await persist(this.db);
|
|
178
|
+
rawSqlite.exec('COMMIT');
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
try {
|
|
182
|
+
rawSqlite.exec('ROLLBACK');
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
normalizeEpics(items) {
|
|
191
|
+
return items
|
|
192
|
+
.map((item) => {
|
|
193
|
+
const id = item.id?.trim();
|
|
194
|
+
if (!id) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const createdAtSource = this.parseIsoDate(item.createdAt);
|
|
198
|
+
return {
|
|
199
|
+
id,
|
|
200
|
+
title: item.title?.trim() || 'Untitled Epic',
|
|
201
|
+
description: item.description ?? null,
|
|
202
|
+
statusId: item.statusId?.trim() || null,
|
|
203
|
+
parentId: item.parentId?.trim() || null,
|
|
204
|
+
agentId: item.agentId?.trim() || null,
|
|
205
|
+
tags: Array.isArray(item.tags) ? item.tags.filter((tag) => typeof tag === 'string') : [],
|
|
206
|
+
createdAtSource,
|
|
207
|
+
};
|
|
208
|
+
})
|
|
209
|
+
.filter((item) => Boolean(item));
|
|
210
|
+
}
|
|
211
|
+
buildStatusMap(items) {
|
|
212
|
+
const map = new Map();
|
|
213
|
+
for (const item of items) {
|
|
214
|
+
const id = item.id?.trim();
|
|
215
|
+
if (!id) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const label = item.label?.trim() || `${UNKNOWN_STATUS_LABEL} (${id})`;
|
|
219
|
+
const color = this.normalizeStatusColor(item.color);
|
|
220
|
+
map.set(id, { label, color });
|
|
221
|
+
}
|
|
222
|
+
return map;
|
|
223
|
+
}
|
|
224
|
+
buildProfileMap(items) {
|
|
225
|
+
const map = new Map();
|
|
226
|
+
for (const item of items) {
|
|
227
|
+
const id = item.id?.trim();
|
|
228
|
+
if (!id) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const name = item.name?.trim();
|
|
232
|
+
map.set(id, name && name.length > 0 ? name : `${UNKNOWN_PROFILE_LABEL} (${id})`);
|
|
233
|
+
}
|
|
234
|
+
return map;
|
|
235
|
+
}
|
|
236
|
+
resolveStatus(statusId, map) {
|
|
237
|
+
if (!statusId) {
|
|
238
|
+
return { label: UNKNOWN_STATUS_LABEL, color: UNKNOWN_STATUS_COLOR };
|
|
239
|
+
}
|
|
240
|
+
return (map.get(statusId) ?? {
|
|
241
|
+
label: `${UNKNOWN_STATUS_LABEL} (${statusId})`,
|
|
242
|
+
color: UNKNOWN_STATUS_COLOR,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
resolveProfileName(profileId, map) {
|
|
246
|
+
if (!profileId) {
|
|
247
|
+
return UNKNOWN_PROFILE_LABEL;
|
|
248
|
+
}
|
|
249
|
+
return map.get(profileId) ?? `${UNKNOWN_PROFILE_LABEL} (${profileId})`;
|
|
250
|
+
}
|
|
251
|
+
normalizeStatusColor(color) {
|
|
252
|
+
const normalized = color?.trim();
|
|
253
|
+
if (normalized && /^#[0-9a-fA-F]{6}$/.test(normalized)) {
|
|
254
|
+
return normalized;
|
|
255
|
+
}
|
|
256
|
+
return UNKNOWN_STATUS_COLOR;
|
|
257
|
+
}
|
|
258
|
+
normalizeAgents(items) {
|
|
259
|
+
return items
|
|
260
|
+
.map((item) => {
|
|
261
|
+
const id = item.id?.trim();
|
|
262
|
+
if (!id) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
id,
|
|
267
|
+
name: item.name?.trim() || null,
|
|
268
|
+
profileId: item.profileId?.trim() || null,
|
|
269
|
+
epicsCompleted: this.toNumberOrNull(item.epicsCompleted),
|
|
270
|
+
completedEpics: this.toNumberOrNull(item.completedEpics),
|
|
271
|
+
activityCount: this.toNumberOrNull(item.activityCount),
|
|
272
|
+
};
|
|
273
|
+
})
|
|
274
|
+
.filter((item) => Boolean(item));
|
|
275
|
+
}
|
|
276
|
+
toNumberOrNull(value) {
|
|
277
|
+
if (typeof value !== 'number' || Number.isNaN(value)) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
return Math.max(0, Math.floor(value));
|
|
281
|
+
}
|
|
282
|
+
parseIsoDate(value) {
|
|
283
|
+
if (!value) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const parsed = new Date(value);
|
|
287
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
return parsed.toISOString();
|
|
291
|
+
}
|
|
292
|
+
async fetchContainerJson(url) {
|
|
293
|
+
const controller = new AbortController();
|
|
294
|
+
const timeout = setTimeout(() => controller.abort(), CONTAINER_FETCH_TIMEOUT_MS);
|
|
295
|
+
try {
|
|
296
|
+
const response = await fetch(url, {
|
|
297
|
+
headers: { accept: 'application/json' },
|
|
298
|
+
signal: controller.signal,
|
|
299
|
+
});
|
|
300
|
+
if (!response.ok) {
|
|
301
|
+
throw new Error(`Container request failed with HTTP ${response.status}`);
|
|
302
|
+
}
|
|
303
|
+
return (await response.json());
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
307
|
+
throw new Error(`Container request timed out after ${CONTAINER_FETCH_TIMEOUT_MS}ms`);
|
|
308
|
+
}
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
clearTimeout(timeout);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async fetchContainerJsonSafe(url) {
|
|
316
|
+
try {
|
|
317
|
+
return await this.fetchContainerJson(url);
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
logger.warn({ error, url }, 'Optional container lookup failed; using fallback values');
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async fetchProfilesForProject(baseUrl, projectId) {
|
|
325
|
+
const primary = await this.fetchContainerJsonSafe(`${baseUrl}/api/agent-profiles?projectId=${projectId}&limit=1000`);
|
|
326
|
+
if (primary?.items && primary.items.length > 0) {
|
|
327
|
+
return primary;
|
|
328
|
+
}
|
|
329
|
+
const fallback = await this.fetchContainerJsonSafe(`${baseUrl}/api/profiles?projectId=${projectId}&limit=1000`);
|
|
330
|
+
if (fallback?.items && fallback.items.length > 0) {
|
|
331
|
+
return fallback;
|
|
332
|
+
}
|
|
333
|
+
return primary ?? fallback;
|
|
334
|
+
}
|
|
335
|
+
async importEpicsIntoMainProject(input) {
|
|
336
|
+
if (process.env.DEVCHAIN_MODE !== 'main') {
|
|
337
|
+
return { imported: 0, skipped: input.epics.length, statusesCreated: 0 };
|
|
338
|
+
}
|
|
339
|
+
if (!this.storage) {
|
|
340
|
+
logger.warn('Main mode epic import skipped because STORAGE_SERVICE is unavailable');
|
|
341
|
+
return { imported: 0, skipped: input.epics.length, statusesCreated: 0 };
|
|
342
|
+
}
|
|
343
|
+
const targetProjectId = await this.resolveMainProjectId();
|
|
344
|
+
if (!targetProjectId) {
|
|
345
|
+
logger.warn({ worktreeId: input.worktreeId }, 'Main mode epic import skipped: no target project');
|
|
346
|
+
return { imported: 0, skipped: input.epics.length, statusesCreated: 0 };
|
|
347
|
+
}
|
|
348
|
+
const existingSourceToTarget = await this.loadExistingMergedEpicMap(targetProjectId, input.worktreeId);
|
|
349
|
+
const statusState = await this.buildStatusState(targetProjectId);
|
|
350
|
+
const mainAgentByName = await this.buildMainAgentMap(targetProjectId);
|
|
351
|
+
const mergeDateIso = new Date().toISOString();
|
|
352
|
+
const pending = new Map(input.epics
|
|
353
|
+
.filter((epic) => !existingSourceToTarget.has(epic.id))
|
|
354
|
+
.map((epic) => [epic.id, epic]));
|
|
355
|
+
let imported = 0;
|
|
356
|
+
const sourceToTargetId = new Map(existingSourceToTarget);
|
|
357
|
+
while (pending.size > 0) {
|
|
358
|
+
let progressed = false;
|
|
359
|
+
for (const [sourceEpicId, epic] of [...pending.entries()]) {
|
|
360
|
+
if (epic.parentId && pending.has(epic.parentId) && !sourceToTargetId.has(epic.parentId)) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
const resolvedStatus = this.resolveStatus(epic.statusId, input.statusById);
|
|
364
|
+
const statusId = await this.ensureMainStatus(targetProjectId, resolvedStatus, statusState);
|
|
365
|
+
const sourceAgentName = epic.agentId
|
|
366
|
+
? (input.agentNameById.get(epic.agentId) ?? null)
|
|
367
|
+
: null;
|
|
368
|
+
const mappedAgentId = sourceAgentName
|
|
369
|
+
? (mainAgentByName.get(sourceAgentName.trim().toLowerCase()) ?? null)
|
|
370
|
+
: null;
|
|
371
|
+
const parentTargetId = epic.parentId && sourceToTargetId.has(epic.parentId)
|
|
372
|
+
? (sourceToTargetId.get(epic.parentId) ?? null)
|
|
373
|
+
: null;
|
|
374
|
+
const mergedTags = this.buildMergedTags(epic.tags, input.worktreeName);
|
|
375
|
+
const mergeResult = await this.createMainEpicWithAtomicDedup({
|
|
376
|
+
projectId: targetProjectId,
|
|
377
|
+
worktreeId: input.worktreeId,
|
|
378
|
+
sourceEpicId,
|
|
379
|
+
createInput: {
|
|
380
|
+
projectId: targetProjectId,
|
|
381
|
+
title: epic.title,
|
|
382
|
+
description: epic.description,
|
|
383
|
+
statusId,
|
|
384
|
+
parentId: parentTargetId,
|
|
385
|
+
agentId: mappedAgentId,
|
|
386
|
+
tags: mergedTags,
|
|
387
|
+
data: {
|
|
388
|
+
mergedFrom: {
|
|
389
|
+
worktreeId: input.worktreeId,
|
|
390
|
+
worktreeName: input.worktreeName,
|
|
391
|
+
sourceEpicId,
|
|
392
|
+
sourceParentEpicId: epic.parentId,
|
|
393
|
+
sourceStatusId: epic.statusId,
|
|
394
|
+
sourceAgentId: epic.agentId,
|
|
395
|
+
sourceAgentName,
|
|
396
|
+
mergedAt: mergeDateIso,
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
skillsRequired: null,
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
sourceToTargetId.set(sourceEpicId, mergeResult.epicId);
|
|
403
|
+
pending.delete(sourceEpicId);
|
|
404
|
+
if (mergeResult.inserted) {
|
|
405
|
+
imported += 1;
|
|
406
|
+
}
|
|
407
|
+
progressed = true;
|
|
408
|
+
}
|
|
409
|
+
if (progressed) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
for (const [sourceEpicId, epic] of [...pending.entries()]) {
|
|
413
|
+
const resolvedStatus = this.resolveStatus(epic.statusId, input.statusById);
|
|
414
|
+
const statusId = await this.ensureMainStatus(targetProjectId, resolvedStatus, statusState);
|
|
415
|
+
const sourceAgentName = epic.agentId
|
|
416
|
+
? (input.agentNameById.get(epic.agentId) ?? null)
|
|
417
|
+
: null;
|
|
418
|
+
const mappedAgentId = sourceAgentName
|
|
419
|
+
? (mainAgentByName.get(sourceAgentName.trim().toLowerCase()) ?? null)
|
|
420
|
+
: null;
|
|
421
|
+
const mergedTags = this.buildMergedTags(epic.tags, input.worktreeName);
|
|
422
|
+
const mergeResult = await this.createMainEpicWithAtomicDedup({
|
|
423
|
+
projectId: targetProjectId,
|
|
424
|
+
worktreeId: input.worktreeId,
|
|
425
|
+
sourceEpicId,
|
|
426
|
+
createInput: {
|
|
427
|
+
projectId: targetProjectId,
|
|
428
|
+
title: epic.title,
|
|
429
|
+
description: epic.description,
|
|
430
|
+
statusId,
|
|
431
|
+
parentId: null,
|
|
432
|
+
agentId: mappedAgentId,
|
|
433
|
+
tags: mergedTags,
|
|
434
|
+
data: {
|
|
435
|
+
mergedFrom: {
|
|
436
|
+
worktreeId: input.worktreeId,
|
|
437
|
+
worktreeName: input.worktreeName,
|
|
438
|
+
sourceEpicId,
|
|
439
|
+
sourceParentEpicId: epic.parentId,
|
|
440
|
+
sourceStatusId: epic.statusId,
|
|
441
|
+
sourceAgentId: epic.agentId,
|
|
442
|
+
sourceAgentName,
|
|
443
|
+
mergedAt: mergeDateIso,
|
|
444
|
+
unresolvedParent: Boolean(epic.parentId),
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
skillsRequired: null,
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
sourceToTargetId.set(sourceEpicId, mergeResult.epicId);
|
|
451
|
+
pending.delete(sourceEpicId);
|
|
452
|
+
if (mergeResult.inserted) {
|
|
453
|
+
imported += 1;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
imported,
|
|
460
|
+
skipped: input.epics.length - imported,
|
|
461
|
+
statusesCreated: statusState.createdCount,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
async createMainEpicWithAtomicDedup(input) {
|
|
465
|
+
if (!this.storage) {
|
|
466
|
+
throw new Error('Storage service is unavailable for main epic import');
|
|
467
|
+
}
|
|
468
|
+
const storage = this.storage;
|
|
469
|
+
const rawSqlite = this.resolveRawSqliteClientForStorage(storage);
|
|
470
|
+
if (!rawSqlite) {
|
|
471
|
+
const created = await storage.createEpic(input.createInput);
|
|
472
|
+
return { epicId: created.id, inserted: true };
|
|
473
|
+
}
|
|
474
|
+
const existingLookup = rawSqlite.prepare(`
|
|
475
|
+
SELECT e.id AS id
|
|
476
|
+
FROM epics e
|
|
477
|
+
WHERE e.project_id = ?
|
|
478
|
+
AND json_extract(json_extract(e.data, '$'), '$.mergedFrom.worktreeId') = ?
|
|
479
|
+
AND json_extract(json_extract(e.data, '$'), '$.mergedFrom.sourceEpicId') = ?
|
|
480
|
+
LIMIT 1
|
|
481
|
+
`);
|
|
482
|
+
return this.runWithSqliteMergeLock(async () => {
|
|
483
|
+
rawSqlite.exec('BEGIN IMMEDIATE TRANSACTION');
|
|
484
|
+
try {
|
|
485
|
+
const existing = existingLookup.get(input.projectId, input.worktreeId, input.sourceEpicId);
|
|
486
|
+
if (existing?.id) {
|
|
487
|
+
rawSqlite.exec('COMMIT');
|
|
488
|
+
return { epicId: existing.id, inserted: false };
|
|
489
|
+
}
|
|
490
|
+
const created = await storage.createEpic(input.createInput);
|
|
491
|
+
rawSqlite.exec('COMMIT');
|
|
492
|
+
return { epicId: created.id, inserted: true };
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
try {
|
|
496
|
+
rawSqlite.exec('ROLLBACK');
|
|
497
|
+
}
|
|
498
|
+
catch {
|
|
499
|
+
}
|
|
500
|
+
throw error;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
async resolveMainProjectId() {
|
|
505
|
+
if (!this.storage) {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
const bootstrapProjectId = this.resolveMainProjectBootstrapService()?.getMainProjectId();
|
|
509
|
+
if (bootstrapProjectId) {
|
|
510
|
+
return bootstrapProjectId;
|
|
511
|
+
}
|
|
512
|
+
const env = (0, env_config_1.getEnvConfig)();
|
|
513
|
+
const repoRoot = (0, path_1.resolve)(env.REPO_ROOT ?? process.cwd());
|
|
514
|
+
const existingByPath = await this.storage.findProjectByPath(repoRoot);
|
|
515
|
+
if (existingByPath) {
|
|
516
|
+
return existingByPath.id;
|
|
517
|
+
}
|
|
518
|
+
const allProjects = await this.storage.listProjects({ limit: 1000, offset: 0 });
|
|
519
|
+
if (allProjects.total > 0 && allProjects.items.length > 0) {
|
|
520
|
+
return allProjects.items[0].id;
|
|
521
|
+
}
|
|
522
|
+
const created = await this.storage.createProject({
|
|
523
|
+
name: (0, path_1.basename)(repoRoot) || 'Main',
|
|
524
|
+
description: 'Auto-created main project for merged worktree epics',
|
|
525
|
+
rootPath: repoRoot,
|
|
526
|
+
isTemplate: false,
|
|
527
|
+
});
|
|
528
|
+
return created.id;
|
|
529
|
+
}
|
|
530
|
+
resolveMainProjectBootstrapService() {
|
|
531
|
+
if (this.mainProjectBootstrap) {
|
|
532
|
+
return this.mainProjectBootstrap;
|
|
533
|
+
}
|
|
534
|
+
if (!this.moduleRef) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
return this.moduleRef.get(main_project_bootstrap_service_1.MainProjectBootstrapService, { strict: false });
|
|
539
|
+
}
|
|
540
|
+
catch {
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
async buildStatusState(projectId) {
|
|
545
|
+
if (!this.storage) {
|
|
546
|
+
return {
|
|
547
|
+
byLabel: new Map(),
|
|
548
|
+
nextPosition: { value: 0 },
|
|
549
|
+
createdCount: 0,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
const allStatuses = [];
|
|
553
|
+
let offset = 0;
|
|
554
|
+
while (true) {
|
|
555
|
+
const page = await this.storage.listStatuses(projectId, {
|
|
556
|
+
limit: SQLITE_STATUS_PAGE_SIZE,
|
|
557
|
+
offset,
|
|
558
|
+
});
|
|
559
|
+
allStatuses.push(...page.items);
|
|
560
|
+
offset += page.items.length;
|
|
561
|
+
if (offset >= page.total || page.items.length === 0) {
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const byLabel = new Map();
|
|
566
|
+
let maxPosition = -1;
|
|
567
|
+
for (const status of allStatuses) {
|
|
568
|
+
byLabel.set(status.label.trim().toLowerCase(), status);
|
|
569
|
+
maxPosition = Math.max(maxPosition, status.position);
|
|
570
|
+
}
|
|
571
|
+
return {
|
|
572
|
+
byLabel,
|
|
573
|
+
nextPosition: { value: maxPosition + 1 },
|
|
574
|
+
createdCount: 0,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
async ensureMainStatus(projectId, resolvedStatus, statusState) {
|
|
578
|
+
if (!this.storage) {
|
|
579
|
+
throw new Error('Storage service is unavailable for main status mapping');
|
|
580
|
+
}
|
|
581
|
+
const normalizedLabel = resolvedStatus.label.trim().toLowerCase();
|
|
582
|
+
const existing = statusState.byLabel.get(normalizedLabel);
|
|
583
|
+
if (existing) {
|
|
584
|
+
return existing.id;
|
|
585
|
+
}
|
|
586
|
+
const created = await this.storage.createStatus({
|
|
587
|
+
projectId,
|
|
588
|
+
label: resolvedStatus.label,
|
|
589
|
+
color: resolvedStatus.color,
|
|
590
|
+
position: statusState.nextPosition.value++,
|
|
591
|
+
});
|
|
592
|
+
statusState.byLabel.set(normalizedLabel, created);
|
|
593
|
+
statusState.createdCount += 1;
|
|
594
|
+
return created.id;
|
|
595
|
+
}
|
|
596
|
+
async buildMainAgentMap(projectId) {
|
|
597
|
+
if (!this.storage) {
|
|
598
|
+
return new Map();
|
|
599
|
+
}
|
|
600
|
+
const byName = new Map();
|
|
601
|
+
let offset = 0;
|
|
602
|
+
while (true) {
|
|
603
|
+
const page = await this.storage.listAgents(projectId, {
|
|
604
|
+
limit: SQLITE_AGENT_PAGE_SIZE,
|
|
605
|
+
offset,
|
|
606
|
+
});
|
|
607
|
+
for (const agent of page.items) {
|
|
608
|
+
const normalized = agent.name.trim().toLowerCase();
|
|
609
|
+
if (!byName.has(normalized)) {
|
|
610
|
+
byName.set(normalized, agent.id);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
offset += page.items.length;
|
|
614
|
+
if (offset >= page.total || page.items.length === 0) {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return byName;
|
|
619
|
+
}
|
|
620
|
+
async loadExistingMergedEpicMap(projectId, worktreeId) {
|
|
621
|
+
if (!this.storage) {
|
|
622
|
+
return new Map();
|
|
623
|
+
}
|
|
624
|
+
const sourceToTarget = new Map();
|
|
625
|
+
let offset = 0;
|
|
626
|
+
while (true) {
|
|
627
|
+
const page = await this.storage.listProjectEpics(projectId, {
|
|
628
|
+
type: 'all',
|
|
629
|
+
limit: SQLITE_EPIC_PAGE_SIZE,
|
|
630
|
+
offset,
|
|
631
|
+
});
|
|
632
|
+
for (const epic of page.items) {
|
|
633
|
+
const sourceEpicId = this.extractSourceEpicId(epic, worktreeId);
|
|
634
|
+
if (sourceEpicId && !sourceToTarget.has(sourceEpicId)) {
|
|
635
|
+
sourceToTarget.set(sourceEpicId, epic.id);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
offset += page.items.length;
|
|
639
|
+
if (offset >= page.total || page.items.length === 0) {
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return sourceToTarget;
|
|
644
|
+
}
|
|
645
|
+
extractSourceEpicId(epic, worktreeId) {
|
|
646
|
+
const data = epic.data;
|
|
647
|
+
if (data && typeof data === 'object' && 'mergedFrom' in data) {
|
|
648
|
+
const mergedFrom = data.mergedFrom;
|
|
649
|
+
if (mergedFrom && typeof mergedFrom === 'object') {
|
|
650
|
+
const mergedWorktreeId = mergedFrom.worktreeId;
|
|
651
|
+
const sourceEpicId = mergedFrom.sourceEpicId;
|
|
652
|
+
if (typeof mergedWorktreeId === 'string' &&
|
|
653
|
+
mergedWorktreeId === worktreeId &&
|
|
654
|
+
typeof sourceEpicId === 'string' &&
|
|
655
|
+
sourceEpicId.trim().length > 0) {
|
|
656
|
+
return sourceEpicId.trim();
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
resolveRawSqliteClientForStorage(storage) {
|
|
663
|
+
const storageWithDb = storage;
|
|
664
|
+
if (!storageWithDb.db) {
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
try {
|
|
668
|
+
return (0, sqlite_raw_1.getRawSqliteClient)(storageWithDb.db);
|
|
669
|
+
}
|
|
670
|
+
catch {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
resolveRawSqliteClientForOrchestratorDb() {
|
|
675
|
+
try {
|
|
676
|
+
const raw = (0, sqlite_raw_1.getRawSqliteClient)(this.db);
|
|
677
|
+
if (!raw || typeof raw.exec !== 'function') {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
return raw;
|
|
681
|
+
}
|
|
682
|
+
catch {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
async runWithSqliteMergeLock(fn) {
|
|
687
|
+
const previous = this.sqliteMergeImportQueue;
|
|
688
|
+
let release;
|
|
689
|
+
this.sqliteMergeImportQueue = new Promise((resolve) => {
|
|
690
|
+
release = resolve;
|
|
691
|
+
});
|
|
692
|
+
await previous;
|
|
693
|
+
try {
|
|
694
|
+
return await fn();
|
|
695
|
+
}
|
|
696
|
+
finally {
|
|
697
|
+
release();
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
buildMergedTags(sourceTags, worktreeName) {
|
|
701
|
+
const tags = new Set();
|
|
702
|
+
for (const tag of sourceTags) {
|
|
703
|
+
const trimmed = tag.trim();
|
|
704
|
+
if (trimmed.length > 0) {
|
|
705
|
+
tags.add(trimmed);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
tags.add(`${MERGED_TAG_PREFIX}${worktreeName}`);
|
|
709
|
+
return [...tags];
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
exports.TaskMergeService = TaskMergeService;
|
|
713
|
+
__decorate([
|
|
714
|
+
(0, event_emitter_1.OnEvent)(task_merge_events_1.WORKTREE_TASK_MERGE_REQUESTED_EVENT, { async: true }),
|
|
715
|
+
__metadata("design:type", Function),
|
|
716
|
+
__metadata("design:paramtypes", [Object]),
|
|
717
|
+
__metadata("design:returntype", Promise)
|
|
718
|
+
], TaskMergeService.prototype, "handleTaskMergeRequested", null);
|
|
719
|
+
exports.TaskMergeService = TaskMergeService = __decorate([
|
|
720
|
+
(0, common_1.Injectable)(),
|
|
721
|
+
__param(0, (0, common_1.Inject)(worktrees_store_1.WORKTREES_STORE)),
|
|
722
|
+
__param(1, (0, common_1.Inject)(orchestrator_provider_1.ORCHESTRATOR_DB_CONNECTION)),
|
|
723
|
+
__param(2, (0, common_1.Optional)()),
|
|
724
|
+
__param(2, (0, common_1.Inject)(storage_interface_1.STORAGE_SERVICE)),
|
|
725
|
+
__param(3, (0, common_1.Optional)()),
|
|
726
|
+
__param(4, (0, common_1.Optional)()),
|
|
727
|
+
__metadata("design:paramtypes", [Object, Object, Object, main_project_bootstrap_service_1.MainProjectBootstrapService,
|
|
728
|
+
core_1.ModuleRef])
|
|
729
|
+
], TaskMergeService);
|
|
730
|
+
//# sourceMappingURL=task-merge.service.js.map
|